Bảo mật API toàn diện 2026 — OWASP Top 10, JWT Hardening và Defense in Depth
Posted on: 4/17/2026 7:13:31 PM
Table of contents
- Mục lục
- 1. Bối cảnh bảo mật API 2026
- 2. OWASP API Security Top 10 — Phân tích chi tiết
- 3. JWT Hardening theo RFC 8725
- 4. CORS, CSP và Security Headers
- 5. Input Validation và Output Encoding
- 6. Kiến trúc Defense in Depth cho API
- 7. Triển khai trên .NET 10 và Vue.js
- 8. Kết luận
1. Bối cảnh bảo mật API 2026
API là xương sống của mọi ứng dụng hiện đại. Từ mobile app đến SPA, từ microservices đến IoT, mọi thứ giao tiếp qua API. Nhưng chính sự phổ biến này khiến API trở thành mục tiêu hàng đầu của các cuộc tấn công. Theo báo cáo của các tổ chức bảo mật, hơn 90% ứng dụng web có ít nhất một lỗ hổng liên quan đến API, và thiệt hại từ các vụ breach thông qua API ngày càng nghiêm trọng.
Tại sao API Security khác Web Security truyền thống?
API không có giao diện người dùng để "che giấu" logic phía sau — attacker tương tác trực tiếp với business logic. Một lỗi authorization trong web form có thể bị hạn chế bởi UI flow, nhưng cùng lỗi đó trong API endpoint cho phép attacker exploit hàng loạt bằng script tự động. Đây là lý do OWASP tách riêng API Security Top 10 khỏi Web Application Top 10.
2. OWASP API Security Top 10 — Phân tích chi tiết
OWASP API Security Top 10 (phiên bản 2023) là danh sách 10 rủi ro bảo mật nghiêm trọng nhất đối với API, được cập nhật từ phiên bản 2019 với nhiều thay đổi quan trọng phản ánh thực tế tấn công mới.
graph TD
A["OWASP API
Security Top 10
(2023)"] --> B["API1
Broken Object Level
Authorization"]
A --> C["API2
Broken
Authentication"]
A --> D["API3
Broken Object Property
Level Authorization"]
A --> E["API4
Unrestricted Resource
Consumption"]
A --> F["API5
Broken Function Level
Authorization"]
A --> G["API6
Unrestricted Access to
Sensitive Business Flows"]
A --> H["API7
Server Side
Request Forgery"]
A --> I["API8
Security
Misconfiguration"]
A --> J["API9
Improper Inventory
Management"]
A --> K["API10
Unsafe Consumption
of APIs"]
style A fill:#e94560,stroke:#fff,color:#fff
style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style F fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style G fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style H fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style I fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style J fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style K fill:#f8f9fa,stroke:#e94560,color:#2c3e50
Sơ đồ 10 rủi ro bảo mật API theo OWASP 2023
API1:2023 — Broken Object Level Authorization (BOLA)
Broken Object Level Authorization
CRITICALĐây là lỗ hổng phổ biến nhất và nguy hiểm nhất. Xảy ra khi API không kiểm tra đúng quyền sở hữu của object mà user đang truy cập. Attacker chỉ cần thay đổi object ID trong request để truy cập dữ liệu của người khác.
Ví dụ tấn công:
// Request hợp lệ — user xem đơn hàng của mình
GET /api/orders/1001
Authorization: Bearer eyJhbGciOi...
// Attacker đổi ID → xem đơn hàng người khác
GET /api/orders/1002
Authorization: Bearer eyJhbGciOi... (cùng token!)
Phòng chống trong .NET 10:
// Authorization handler kiểm tra ownership
public class OrderOwnerHandler : AuthorizationHandler<OrderOwnerRequirement, Order>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OrderOwnerRequirement requirement,
Order order)
{
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (order.UserId == userId)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
// Sử dụng trong controller
[HttpGet("{id}")]
public async Task<IActionResult> GetOrder(int id)
{
var order = await _repo.GetByIdAsync(id);
var authResult = await _authService
.AuthorizeAsync(User, order, "OrderOwner");
if (!authResult.Succeeded) return Forbid();
return Ok(order);
}
API2:2023 — Broken Authentication
Broken Authentication
CRITICALAPI authentication yếu hoặc thiếu cho phép attacker giả mạo danh tính. Các lỗi thường gặp: không validate JWT signature, chấp nhận token hết hạn, brute-force không bị chặn, credential stuffing.
Những sai lầm phổ biến khi implement authentication:
| Sai lầm | Hậu quả | Cách khắc phục |
|---|---|---|
Không validate JWT alg header | Attacker đổi sang "alg":"none" để bypass signature | Whitelist algorithms, reject none |
| Secret key yếu hoặc hardcode | Brute-force secret → forge token | Dùng RSA/ECDSA, rotate key định kỳ |
Không kiểm tra exp claim | Token cũ vẫn hợp lệ mãi mãi | Validate expiration, dùng short-lived tokens |
| Không rate limit endpoint login | Credential stuffing, brute-force password | Rate limiting + account lockout + CAPTCHA |
| Token trong URL query string | Token bị log trong server logs, browser history, referer header | Chỉ truyền token qua Authorization header |
API3:2023 — Broken Object Property Level Authorization
Broken Object Property Level Authorization
HIGHGộp từ 2 lỗi cũ: Excessive Data Exposure (API trả về quá nhiều field) và Mass Assignment (API chấp nhận field không mong muốn). Đây là hậu quả của việc bind request/response trực tiếp với database entity.
// SAI — trả về toàn bộ entity kể cả field nhạy cảm
[HttpGet("{id}")]
public async Task<User> GetUser(int id)
=> await _db.Users.FindAsync(id);
// Response chứa: PasswordHash, SSN, InternalNotes...
// ĐÚNG — dùng DTO chỉ chứa field cần thiết
[HttpGet("{id}")]
public async Task<UserDto> GetUser(int id)
{
var user = await _db.Users.FindAsync(id);
return new UserDto(user.Id, user.Name, user.Email);
}
// SAI — Mass Assignment: bind trực tiếp request body
[HttpPut("{id}")]
public async Task UpdateUser(int id, [FromBody] User user) { ... }
// Attacker gửi: {"role": "admin", "isVerified": true}
// ĐÚNG — dùng DTO với field được phép
[HttpPut("{id}")]
public async Task UpdateUser(int id, [FromBody] UpdateUserDto dto) { ... }
// UpdateUserDto chỉ có: Name, Email, Avatar
API4:2023 — Unrestricted Resource Consumption
API không giới hạn tài nguyên sẽ bị khai thác cho DoS, bill shock (trên cloud), hoặc đơn giản là làm sập hệ thống. Cần kiểm soát: số lượng request, kích thước request body, số record trả về, thời gian xử lý, file upload size.
// .NET 10 — Rate Limiting middleware tích hợp sẵn
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("api", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueLimit = 0;
});
options.AddTokenBucketLimiter("upload", opt =>
{
opt.TokenLimit = 10;
opt.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
opt.TokensPerPeriod = 2;
});
options.RejectionStatusCode = 429;
});
// Giới hạn request body size
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
});
API5-API10 — Tổng hợp nhanh
| Risk | Mô tả | Phòng chống chính |
|---|---|---|
| API5: Broken Function Level Authorization | User thường truy cập được endpoint admin | RBAC/ABAC, kiểm tra role ở mọi endpoint |
| API6: Unrestricted Access to Sensitive Business Flows | Bot mua hàng, spam đăng ký, scraping | CAPTCHA, device fingerprint, business logic rate limit |
| API7: Server Side Request Forgery (SSRF) | API fetch URL do user cung cấp → truy cập internal service | Whitelist domains, block internal IPs, dùng allowlist |
| API8: Security Misconfiguration | CORS *, debug mode on prod, default credentials | Hardening checklist, automated scanning, IaC |
| API9: Improper Inventory Management | API cũ, shadow API, undocumented endpoints | API gateway, OpenAPI spec, deprecation policy |
| API10: Unsafe Consumption of APIs | Trust nhầm data từ third-party API | Validate response từ external API, timeout, circuit breaker |
3. JWT Hardening theo RFC 8725
JSON Web Token là phương thức authentication phổ biến nhất cho API. Nhưng JWT có rất nhiều cách bị khai thác nếu implement sai. RFC 8725 (JSON Web Token Best Current Practices) đưa ra các guidelines quan trọng cần tuân thủ.
sequenceDiagram
participant C as Client (Vue.js)
participant A as Auth Server
participant API as API Server (.NET)
participant DB as Database
C->>A: POST /token (credentials)
A->>A: Validate credentials
A->>A: Generate JWT (RS256, short exp)
A-->>C: Access Token + Refresh Token
C->>API: GET /api/data
Authorization: Bearer {JWT}
API->>API: Validate signature (public key)
API->>API: Check exp, iss, aud, nbf
API->>API: Extract claims, check permissions
API->>DB: Query with user context
DB-->>API: Filtered data
API-->>C: 200 OK + data
Note over C,API: Token hết hạn sau 15 phút
C->>A: POST /token/refresh
A->>A: Validate refresh token
A->>A: Issue new access token
A-->>C: New Access Token
Luồng JWT authentication chuẩn với access token ngắn hạn và refresh token
Checklist JWT Hardening
JWT Security Checklist
- Algorithm: Dùng RS256 hoặc ES256 (asymmetric). Tuyệt đối không dùng HS256 với secret yếu. Reject
"alg":"none". - Expiration: Access token: 15-30 phút. Refresh token: 7-30 ngày. Luôn validate
expclaim. - Audience (
aud): Mỗi API phải validateaudclaim match với chính nó — ngăn token dùng cho service A bị dùng ở service B. - Issuer (
iss): Validate issuer để đảm bảo token đến từ auth server tin cậy. - Not Before (
nbf): Setnbf= thời điểm issue để ngăn token bị dùng trước thời điểm tạo. - JTI (JWT ID): Unique ID cho mỗi token, lưu vào blacklist khi revoke.
- Claims: Chỉ đưa thông tin cần thiết vào payload. KHÔNG đưa password, PII nhạy cảm, hay internal IDs.
- Key Rotation: Rotate signing keys định kỳ. Publish public keys qua JWKS endpoint với
kidheader.
Cấu hình JWT Authentication trong .NET 10:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://auth.example.com";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://auth.example.com",
ValidateAudience = true,
ValidAudience = "https://api.example.com",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30),
ValidateIssuerSigningKey = true,
ValidAlgorithms = new[] { "RS256", "ES256" },
RequireExpirationTime = true,
RequireSignedTokens = true,
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception is SecurityTokenExpiredException)
context.Response.Headers["X-Token-Expired"] = "true";
return Task.CompletedTask;
}
};
});
// Fallback policy — mọi endpoint đều yêu cầu authentication
builder.Services.AddAuthorizationBuilder()
.SetFallbackPolicy(new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build());
Cảnh báo: JWT không phải session
JWT là stateless — một khi đã issue, server không thể thu hồi cho đến khi hết hạn. Nếu cần revoke ngay lập tức (user bị ban, đổi password), phải dùng thêm token blacklist hoặc short-lived token + refresh rotation. Đừng đặt exp quá dài (24h+) để tránh khoảng "zombie token" quá lớn.
4. CORS, CSP và Security Headers
CORS — Cross-Origin Resource Sharing
CORS là cơ chế trình duyệt dùng để kiểm soát cross-origin request. Cấu hình CORS sai là một trong những lỗi Security Misconfiguration (API8) phổ biến nhất.
sequenceDiagram
participant B as Browser
participant API as API Server
Note over B,API: Preflight Request (PUT/DELETE/custom headers)
B->>API: OPTIONS /api/data
Origin: https://app.example.com
Access-Control-Request-Method: PUT
API->>API: Kiểm tra origin có trong allowlist?
API-->>B: 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Max-Age: 3600
Note over B,API: Actual Request
B->>API: PUT /api/data
Origin: https://app.example.com
API-->>B: 200 OK
Access-Control-Allow-Origin: https://app.example.com
Luồng CORS preflight request và actual request
| Cấu hình | Rủi ro | Recommendation |
|---|---|---|
Access-Control-Allow-Origin: * | Mọi domain đều gọi được API | Chỉ dùng cho public API không cần auth |
| Reflect Origin header nguyên bản | Bypass CORS hoàn toàn — tương đương * | Whitelist cụ thể từng origin |
Allow-Credentials: true + Origin: * | Browser block (không hợp lệ), nhưng developer bypass = reflect | Credentials chỉ đi cùng specific origin |
Không set Max-Age | Browser gửi preflight mỗi request → latency tăng | Set Max-Age: 3600 (1 giờ) |
Cấu hình CORS đúng trong .NET 10:
builder.Services.AddCors(options =>
{
options.AddPolicy("Production", policy =>
{
policy
.WithOrigins(
"https://app.example.com",
"https://admin.example.com"
)
.WithMethods("GET", "POST", "PUT", "DELETE")
.WithHeaders("Authorization", "Content-Type", "X-Request-Id")
.SetPreflightMaxAge(TimeSpan.FromHours(1))
.AllowCredentials();
});
});
Security Headers cần thiết
Ngoài CORS, một loạt HTTP headers khác giúp bảo vệ API và client:
// Security headers middleware cho .NET 10
app.Use(async (context, next) =>
{
var headers = context.Response.Headers;
// Chống clickjacking
headers["X-Frame-Options"] = "DENY";
// Chống MIME type sniffing
headers["X-Content-Type-Options"] = "nosniff";
// Content Security Policy
headers["Content-Security-Policy"] =
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'";
// Strict Transport Security (HTTPS only)
headers["Strict-Transport-Security"] =
"max-age=31536000; includeSubDomains; preload";
// Ngăn browser gửi Referer chứa thông tin nhạy cảm
headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
// Tắt một số browser API không cần thiết
headers["Permissions-Policy"] =
"camera=(), microphone=(), geolocation=()";
await next();
});
5. Input Validation và Output Encoding
Input Validation là tuyến phòng thủ đầu tiên chống Injection attacks (SQL Injection, NoSQL Injection, Command Injection, XSS). Nguyên tắc cốt lõi: Never trust user input — validate tất cả dữ liệu đến từ bên ngoài hệ thống.
graph LR
A["Client Input"] --> B["Schema
Validation"]
B --> C["Type
Checking"]
C --> D["Business
Rules"]
D --> E["Sanitization"]
E --> F["Safe Data"]
B -->|Invalid| G["400
Bad Request"]
C -->|Invalid| G
D -->|Invalid| G
style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style F fill:#4CAF50,stroke:#fff,color:#fff
style G fill:#e94560,stroke:#fff,color:#fff
Pipeline validation dữ liệu đầu vào
Validation trong .NET 10 — FluentValidation + Minimal API
// DTO với validation attributes
public record CreateOrderRequest(
[Required, StringLength(200)] string ProductName,
[Range(1, 1000)] int Quantity,
[Required, EmailAddress] string CustomerEmail,
[RegularExpression(@"^[a-zA-Z0-9\-]+$")] string? CouponCode
);
// FluentValidation cho business rules phức tạp
public class CreateOrderValidator : AbstractValidator<CreateOrderRequest>
{
public CreateOrderValidator()
{
RuleFor(x => x.ProductName)
.NotEmpty()
.MaximumLength(200)
.Must(name => !name.Contains("<script>"))
.WithMessage("Product name contains invalid characters");
RuleFor(x => x.Quantity)
.InclusiveBetween(1, 1000);
RuleFor(x => x.CustomerEmail)
.EmailAddress(EmailValidationMode.AspNetCoreCompatible);
RuleFor(x => x.CouponCode)
.Matches(@"^[A-Z0-9\-]{4,20}$")
.When(x => x.CouponCode != null);
}
}
// Minimal API endpoint với validation
app.MapPost("/api/orders", async (
CreateOrderRequest request,
IValidator<CreateOrderRequest> validator,
OrderService service) =>
{
var result = await validator.ValidateAsync(request);
if (!result.IsValid)
return Results.ValidationProblem(result.ToDictionary());
var order = await service.CreateAsync(request);
return Results.Created($"/api/orders/{order.Id}", order);
});
Chống SQL Injection — Parameterized Queries
SQL Injection vẫn là mối đe dọa #1
Dù năm 2026, SQL Injection vẫn nằm trong top lỗ hổng phổ biến nhất. Nguyên nhân chính: developer vẫn nối chuỗi SQL thay vì dùng parameterized queries. ORM như Entity Framework Core giúp ngăn phần lớn, nhưng raw SQL vẫn cần cẩn thận.
// SAI — SQL Injection vulnerability
var sql = $"SELECT * FROM Users WHERE Name = '{name}'";
// Input: ' OR '1'='1' -- → trả về toàn bộ users
// ĐÚNG — Parameterized query với EF Core
var users = await _db.Users
.Where(u => u.Name == name)
.ToListAsync();
// ĐÚNG — Raw SQL với parameter
var users = await _db.Users
.FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {name}")
.ToListAsync();
Chống XSS trong Vue.js
<!-- SAI — v-html render HTML không sanitize -->
<div v-html="userComment"></div>
<!-- Input: <img src=x onerror=alert(document.cookie)> → XSS! -->
<!-- ĐÚNG — Vue template tự escape mặc định -->
<div>{{ userComment }}</div>
<!-- Output: <img src=x onerror=alert(...)> → safe -->
<!-- Nếu PHẢI render HTML (rich text editor): dùng DOMPurify -->
<script setup>
import DOMPurify from 'dompurify';
const safeHtml = computed(() =>
DOMPurify.sanitize(userComment.value, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'target', 'rel']
})
);
</script>
<div v-html="safeHtml"></div>
6. Kiến trúc Defense in Depth cho API
Không có một biện pháp bảo mật nào là đủ. Defense in Depth đặt nhiều lớp bảo vệ chồng chéo — khi một lớp bị bypass, lớp tiếp theo vẫn chặn được attacker.
graph TB
subgraph L1["Layer 1: Network"]
WAF["WAF
(Cloudflare/AWS WAF)"]
DDoS["DDoS
Protection"]
TLS["TLS 1.3
Termination"]
end
subgraph L2["Layer 2: API Gateway"]
RL["Rate
Limiting"]
AUTH["Authentication
(JWT/OAuth)"]
CORS2["CORS
Enforcement"]
end
subgraph L3["Layer 3: Application"]
AUTHZ["Authorization
(RBAC/ABAC)"]
VAL["Input
Validation"]
BIZ["Business Logic
Guards"]
end
subgraph L4["Layer 4: Data"]
ENC["Encryption
at Rest"]
MASK["Data
Masking"]
AUDIT["Audit
Logging"]
end
L1 --> L2 --> L3 --> L4
style L1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style L2 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style L3 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style L4 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style WAF fill:#e94560,stroke:#fff,color:#fff
style DDoS fill:#e94560,stroke:#fff,color:#fff
style TLS fill:#e94560,stroke:#fff,color:#fff
style RL fill:#2c3e50,stroke:#fff,color:#fff
style AUTH fill:#2c3e50,stroke:#fff,color:#fff
style CORS2 fill:#2c3e50,stroke:#fff,color:#fff
style AUTHZ fill:#4CAF50,stroke:#fff,color:#fff
style VAL fill:#4CAF50,stroke:#fff,color:#fff
style BIZ fill:#4CAF50,stroke:#fff,color:#fff
style ENC fill:#16213e,stroke:#fff,color:#fff
style MASK fill:#16213e,stroke:#fff,color:#fff
style AUDIT fill:#16213e,stroke:#fff,color:#fff
Kiến trúc 4 lớp Defense in Depth cho API production
Chi tiết từng lớp
Layer 1 — Network: WAF (Web Application Firewall) như Cloudflare WAF hoặc AWS WAF đặt trước API, chặn các attack pattern đã biết (SQL Injection, XSS, path traversal) trước khi request đến application. DDoS Protection (Cloudflare cung cấp miễn phí ở tất cả các plan) hấp thụ traffic bất thường. TLS 1.3 mã hóa toàn bộ traffic.
Layer 2 — API Gateway: Tập trung xác thực (authentication), rate limiting, và CORS enforcement. API Gateway đóng vai trò single entry point, giúp áp dụng policy nhất quán cho tất cả endpoints. Trong .NET 10, có thể dùng YARP (Yet Another Reverse Proxy) hoặc Ocelot.
Layer 3 — Application: Authorization chi tiết (ai được làm gì trên resource nào), input validation, và business logic guards (ví dụ: user không thể tự tăng balance, order quantity không thể âm).
Layer 4 — Data: Mã hóa dữ liệu nhạy cảm ở database (SQL Server Always Encrypted, Azure Key Vault), data masking cho môi trường staging/dev, và audit log ghi lại mọi thao tác quan trọng để forensics khi cần.
7. Triển khai trên .NET 10 và Vue.js
Security Pipeline trong .NET 10
Thứ tự middleware trong ASP.NET Core rất quan trọng — security middleware phải đặt đúng vị trí:
var app = builder.Build();
// 1. Exception Handler (đầu tiên — bắt mọi lỗi)
app.UseExceptionHandler("/error");
// 2. HSTS (redirect HTTP → HTTPS)
app.UseHsts();
app.UseHttpsRedirection();
// 3. Security Headers (custom middleware)
app.UseSecurityHeaders();
// 4. CORS (trước Authentication)
app.UseCors("Production");
// 5. Rate Limiting
app.UseRateLimiter();
// 6. Authentication (xác thực danh tính)
app.UseAuthentication();
// 7. Authorization (kiểm tra quyền)
app.UseAuthorization();
// 8. Endpoints
app.MapControllers();
Mẹo: Sử dụng Problem Details cho Security Errors
.NET 10 hỗ trợ RFC 9457 (Problem Details) cho error response. Khi trả về lỗi security, KHÔNG bao giờ leak thông tin internal: không trả về stack trace, tên table, hay chi tiết query. Chỉ trả về đủ thông tin cho client xử lý.
// Global exception handler — không leak internal details
app.MapGet("/error", (HttpContext context) =>
{
var error = context.Features.Get<IExceptionHandlerFeature>()?.Error;
return Results.Problem(
title: "An error occurred",
statusCode: 500,
detail: "Please contact support with the trace ID.",
extensions: new Dictionary<string, object?>
{
["traceId"] = Activity.Current?.Id ?? context.TraceIdentifier
}
);
});
Security Patterns trong Vue.js
// composables/useAuth.ts — Secure token management
import { ref, computed } from 'vue';
const accessToken = ref<string | null>(null);
const refreshToken = ref<string | null>(null);
export function useAuth() {
// KHÔNG lưu token vào localStorage (XSS accessible)
// Dùng in-memory + httpOnly cookie cho refresh token
const isAuthenticated = computed(() => !!accessToken.value);
async function login(email: string, password: string) {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // gửi httpOnly cookie
body: JSON.stringify({ email, password })
});
if (!response.ok) throw new Error('Login failed');
const data = await response.json();
accessToken.value = data.accessToken;
// refreshToken nằm trong httpOnly cookie, JS không access được
}
async function fetchWithAuth(url: string, options: RequestInit = {}) {
const headers = new Headers(options.headers);
if (accessToken.value) {
headers.set('Authorization', `Bearer ${accessToken.value}`);
}
let response = await fetch(url, {
...options,
headers,
credentials: 'include'
});
// Auto-refresh nếu 401
if (response.status === 401) {
await refreshAccessToken();
headers.set('Authorization', `Bearer ${accessToken.value}`);
response = await fetch(url, {
...options,
headers,
credentials: 'include'
});
}
return response;
}
return { isAuthenticated, login, fetchWithAuth };
}
Checklist bảo mật API trước khi lên Production
| Hạng mục | Kiểm tra | Công cụ |
|---|---|---|
| Authentication | JWT validate đúng (alg, exp, iss, aud), không chấp nhận unsigned token | jwt.io debugger, Burp Suite |
| Authorization | Mọi endpoint đều check quyền, test BOLA bằng ID enumeration | OWASP ZAP, Postman scripts |
| Input Validation | Từ chối input ngoài schema, test SQL Injection/XSS payloads | SQLMap, XSStrike, Burp Scanner |
| CORS | Không wildcard * cho API cần auth, test với origin lạ | curl manual test, CORS tester |
| Rate Limiting | Chặn >100 requests/phút/IP, test burst traffic | ab (Apache Bench), k6 |
| Security Headers | HSTS, X-Content-Type-Options, CSP, X-Frame-Options | securityheaders.com, Mozilla Observatory |
| Error Handling | Không leak stack trace, DB schema, internal paths | Manual testing, Sentry config |
| Logging | Log authentication failures, authorization denials, KHÔNG log tokens/passwords | Structured logging, SIEM |
| Dependencies | Không có known CVE trong NuGet/npm packages | dotnet audit, npm audit, Snyk |
| TLS | TLS 1.2+ only, strong cipher suites, valid certificate | SSL Labs, testssl.sh |
8. Kết luận
Bảo mật API không phải việc "thêm vào sau" — nó phải được thiết kế từ đầu, embed vào mọi layer của hệ thống. OWASP API Security Top 10 là framework tuyệt vời để đánh giá và cải thiện bảo mật API một cách có hệ thống. Kết hợp với JWT hardening theo RFC 8725, CORS/CSP đúng cách, input validation nghiêm ngặt, và kiến trúc Defense in Depth, chúng ta có thể xây dựng API an toàn cho production mà vẫn giữ được developer experience tốt.
Hãy nhớ: security là một quá trình liên tục, không phải một trạng thái đạt được. Audit định kỳ, cập nhật dependencies, và theo dõi OWASP cùng các advisory bảo mật là việc phải làm thường xuyên.
Tóm tắt nhanh
- OWASP API Security Top 10 (2023) là kim chỉ nam — BOLA (#1) và Broken Authentication (#2) là phổ biến nhất
- JWT: dùng RS256/ES256, short-lived tokens, validate đủ claims (exp, iss, aud, nbf)
- CORS: whitelist origin cụ thể, không wildcard cho API cần auth
- Input Validation: validate ở boundary, parameterized queries cho SQL, DOMPurify cho HTML
- Defense in Depth: WAF → API Gateway → Application → Data — mỗi layer chặn một loại attack
Nguồn tham khảo
- OWASP API Security Top 10 — 2023
- RFC 8725 — JSON Web Token Best Current Practices
- Authentication and authorization in Minimal APIs — Microsoft Learn
- .NET 10: What's New for Authentication and Authorization — Auth0
- Content Security Policy (CSP) — MDN Web Docs
- Master API Security: Essential Best Practices for 2026
Vite+ 2026 — Một Toolchain Duy Nhất Thay Thế Webpack, ESLint và Prettier
Cloudflare AI Platform 2026 — Hạ tầng Edge cho AI Agent Serverless
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.