Developer Tools

Giải Thích JWT Tokens: Cấu Trúc, Bảo Mật và Những Lỗi Thường Gặp

Tìm hiểu cách JSON Web Tokens hoạt động, nội dung bên trong chúng, và những cạm bẫy bảo mật khiến các lập trình viên gặp rắc rối khi triển khai thực tế.

8 phút đọc

Security lock on a circuit board

JSON Web Tokens (JWTs) có mặt ở khắp nơi — chúng hỗ trợ xác thực trong các SPA, ứng dụng di động và kiến trúc microservice trên toàn thế giới. Thế nhưng đây cũng là một trong những cơ chế bảo mật bị hiểu nhầm nhiều nhất trong phát triển web. Dùng sai có thể dẫn đến bỏ qua xác thực, leo thang đặc quyền, hoặc chiếm đoạt toàn bộ tài khoản.

JWT là gì?

JWT là một chuỗi nhỏ gọn, an toàn với URL, mã hóa một tập hợp các claims — những khẳng định về người dùng hoặc phiên làm việc. Nó trông như thế này:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Đây là ba đoạn được mã hóa Base64URL, ngăn cách nhau bằng dấu chấm:

  1. Header — thuật toán và loại token
  2. Payload — các claims (dữ liệu người dùng)
  3. Signature — bằng chứng mật mã về tính toàn vẹn

Dán bất kỳ JWT nào vào JWT Decoder của chúng tôi để kiểm tra ngay cả ba phần mà không cần liên hệ với bất kỳ máy chủ bên ngoài nào.

Cấu trúc của một JWT

{
  "alg": "HS256",
  "typ": "JWT"
}

alg chỉ định thuật toán ký. Các giá trị phổ biến:

  • HS256 — HMAC với SHA-256 (đối xứng, dùng chung một secret)
  • RS256 — RSA với SHA-256 (bất đối xứng, khóa công khai/riêng tư)
  • ES256 — ECDSA với SHA-256 (bất đối xứng, khóa nhỏ hơn)

Payload

{
  "sub": "user_abc123",
  "email": "alice@example.com",
  "role": "admin",
  "iat": 1711670400,
  "exp": 1711756800
}

Các claims chuẩn đã được đăng ký:

Claim Ý nghĩa
sub Subject (token dành cho ai)
iss Issuer (ai đã tạo token)
aud Audience (ai được phép chấp nhận token)
exp Thời gian hết hạn (Unix timestamp)
iat Thời điểm phát hành (Unix timestamp)
nbf Not before (không chấp nhận trước thời điểm này)

Signature

Với HS256:

HMAC-SHA256(base64url(header) + "." + base64url(payload), secret)

Signature chứng minh token chưa bị giả mạo. Payload KHÔNG được mã hóa — nó chỉ được encode. Bất kỳ ai cũng có thể đọc được.

Tuyệt đối không lưu dữ liệu nhạy cảm như mật khẩu hay số thẻ tín dụng trong JWT payload.

HS256 vs. RS256: nên chọn cái nào?

HS256 sử dụng một secret dùng chung. Mọi dịch vụ cần xác minh token đều phải có cùng secret đó. Đơn giản cho các ứng dụng monolith, nhưng nguy hiểm trong kiến trúc đa dịch vụ — nếu bất kỳ dịch vụ nào bị xâm phạm, kẻ tấn công có thể giả mạo token.

RS256 sử dụng cặp khóa bất đối xứng. Máy chủ xác thực ký bằng khóa riêng tư; tất cả các dịch vụ khác xác minh bằng khóa công khai. Việc một dịch vụ tiêu thụ bị xâm phạm không cho phép kẻ tấn công giả mạo token. Ưu tiên dùng RS256 cho bất kỳ hệ thống nào có nhiều dịch vụ.

Lỗ hổng alg: none

Một trong những cuộc tấn công JWT khét tiếng nhất. Một số thư viện cũ chấp nhận token với "alg": "none" và không có signature — coi nó là hợp lệ. Kẻ tấn công có thể tạo ra:

{ "alg": "none" }

với bất kỳ payload nào và vượt qua xác thực hoàn toàn.

Cách khắc phục: Luôn chỉ định rõ ràng các thuật toán được phép trong thư viện JWT của bạn. Không bao giờ chấp nhận none.

// ❌ Nguy hiểm
jwt.verify(token, secret);

// ✅ An toàn — chỉ chấp nhận HS256
jwt.verify(token, secret, { algorithms: ["HS256"] });

Tấn công nhầm lẫn thuật toán

Một lỗ hổng nghiêm trọng khác: nếu thư viện của bạn tự động phát hiện thuật toán từ header, kẻ tấn công có thể đổi RS256 thành HS256 và ký token bằng khóa công khai làm HMAC secret (vốn dĩ là công khai theo định nghĩa).

Cách khắc phục: Luôn hardcode thuật toán dự kiến. Không bao giờ tin tưởng header alg.

Lưu trữ token: nên để JWT ở đâu

Nơi lưu trữ Rủi ro XSS Rủi ro CSRF Ghi chú
localStorage Cao Không có Mọi JS trên trang đều truy cập được
sessionStorage Cao Không có Bị xóa khi đóng tab
HTTP-only cookie Không có Trung bình Tốt nhất cho web app; dùng SameSite=Strict
Memory (biến) Thấp Không có Mất khi làm mới trang; dành cho SPA

Với ứng dụng web, HTTP-only cookies với SameSite=Strict là lựa chọn an toàn nhất. Với ứng dụng native, nên dùng các API lưu trữ bảo mật (Keychain, Keystore).

Hết hạn và refresh tokens

Access token có thời hạn ngắn (5–15 phút) kết hợp với refresh token có thời hạn dài là mô hình chuẩn:

  1. Người dùng đăng nhập → máy chủ cấp access token (15 phút) + refresh token (7 ngày, lưu trong DB)
  2. Client dùng access token cho các API call
  3. Khi access token hết hạn, client gửi refresh token → nhận access token mới
  4. Khi đăng xuất, vô hiệu hóa refresh token trong database

Cách này giới hạn thiệt hại nếu access token bị đánh cắp.

Thu hồi JWTs

JWT là stateless — một khi đã phát hành, chúng hợp lệ cho đến khi hết hạn. Đây là một sự đánh đổi. Các lựa chọn để thu hồi sớm:

  • Blocklist — lưu các giá trị JTI (JWT ID) đã bị vô hiệu hóa trong Redis. Kiểm tra mỗi request.
  • Thời hạn ngắn — token 5 phút giảm thiểu phạm vi thiệt hại.
  • Refresh token rotation — phát hiện việc tái sử dụng token đã được xoay vòng như một dấu hiệu bị đánh cắp.

Gỡ lỗi với JWT Decoder

Khi gỡ lỗi các vấn đề xác thực, hãy dùng JWT Decoder của chúng tôi để:

  • Kiểm tra toàn bộ payload mà không cần viết code
  • Xem timestamps hết hạn ở dạng dễ đọc
  • Xác minh thuật toán đang được sử dụng
  • Phát hiện các claims không mong muốn hoặc còn thiếu

Tất cả quá trình giải mã diễn ra cục bộ trên trình duyệt của bạn — token không bao giờ rời khỏi máy của bạn.

Checklist bảo mật JWT

  • Dùng RS256 hoặc ES256 cho kiến trúc đa dịch vụ
  • Chỉ định rõ ràng các thuật toán được phép trong thư viện của bạn
  • Xác thực các claims exp, issaud trên mỗi request
  • Lưu token trong HTTP-only cookies cho web app
  • Sử dụng thời hạn access token ngắn (15 phút hoặc ít hơn)
  • Triển khai refresh token rotation với tính năng phát hiện tái sử dụng
  • Không bao giờ đưa dữ liệu nhạy cảm vào payload
  • Dùng HTTPS ở mọi nơi — token dạng plaintext cũng như không có xác thực

JWT mạnh mẽ và tiện lợi, nhưng mức độ bảo mật phụ thuộc hoàn toàn vào cách triển khai. Hiểu rõ cấu trúc, nắm vững các kiểu tấn công, và lớp xác thực của bạn sẽ vững chắc.