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

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.

91% Ứng dụng web có lỗ hổng API
681% Tăng trưởng API traffic (2021-2025)
$4.45M Chi phí trung bình mỗi data breach
74% Tổ chức gặp ít nhất 3 API breaches

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

CRITICAL

API 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ầmHậu quảCách khắc phục
Không validate JWT alg headerAttacker đổi sang "alg":"none" để bypass signatureWhitelist algorithms, reject none
Secret key yếu hoặc hardcodeBrute-force secret → forge tokenDùng RSA/ECDSA, rotate key định kỳ
Không kiểm tra exp claimToken cũ vẫn hợp lệ mãi mãiValidate expiration, dùng short-lived tokens
Không rate limit endpoint loginCredential stuffing, brute-force passwordRate limiting + account lockout + CAPTCHA
Token trong URL query stringToken bị log trong server logs, browser history, referer headerChỉ truyền token qua Authorization header

API3:2023 — Broken Object Property Level Authorization

Broken Object Property Level Authorization

HIGH

Gộ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

RiskMô tảPhòng chống chính
API5: Broken Function Level AuthorizationUser thường truy cập được endpoint adminRBAC/ABAC, kiểm tra role ở mọi endpoint
API6: Unrestricted Access to Sensitive Business FlowsBot mua hàng, spam đăng ký, scrapingCAPTCHA, device fingerprint, business logic rate limit
API7: Server Side Request Forgery (SSRF)API fetch URL do user cung cấp → truy cập internal serviceWhitelist domains, block internal IPs, dùng allowlist
API8: Security MisconfigurationCORS *, debug mode on prod, default credentialsHardening checklist, automated scanning, IaC
API9: Improper Inventory ManagementAPI cũ, shadow API, undocumented endpointsAPI gateway, OpenAPI spec, deprecation policy
API10: Unsafe Consumption of APIsTrust nhầm data từ third-party APIValidate 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 exp claim.
  • Audience (aud): Mỗi API phải validate aud claim 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): Set nbf = 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 kid header.

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ìnhRủi roRecommendation
Access-Control-Allow-Origin: *Mọi domain đều gọi được APIChỉ dùng cho public API không cần auth
Reflect Origin header nguyên bảnBypass 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 = reflectCredentials chỉ đi cùng specific origin
Không set Max-AgeBrowser gửi preflight mỗi request → latency tăngSet 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: &lt;img src=x onerror=alert(...)&gt; → 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ụcKiểm traCông cụ
AuthenticationJWT validate đúng (alg, exp, iss, aud), không chấp nhận unsigned tokenjwt.io debugger, Burp Suite
AuthorizationMọi endpoint đều check quyền, test BOLA bằng ID enumerationOWASP ZAP, Postman scripts
Input ValidationTừ chối input ngoài schema, test SQL Injection/XSS payloadsSQLMap, XSStrike, Burp Scanner
CORSKhông wildcard * cho API cần auth, test với origin lạcurl manual test, CORS tester
Rate LimitingChặn >100 requests/phút/IP, test burst trafficab (Apache Bench), k6
Security HeadersHSTS, X-Content-Type-Options, CSP, X-Frame-Optionssecurityheaders.com, Mozilla Observatory
Error HandlingKhông leak stack trace, DB schema, internal pathsManual testing, Sentry config
LoggingLog authentication failures, authorization denials, KHÔNG log tokens/passwordsStructured logging, SIEM
DependenciesKhông có known CVE trong NuGet/npm packagesdotnet audit, npm audit, Snyk
TLSTLS 1.2+ only, strong cipher suites, valid certificateSSL 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