-1

Bảo mật trong lưu trữ JWT token (access token / refresh token) , so sánh chi tiết giữa cookie và localStorage

Khi nói đến bảo mật trong lưu trữ JWT token (access token / refresh token) trong trình duyệt, bạn cần cân nhắc giữa bảo mật (security)trải nghiệm người dùng (UX). Dưới đây là so sánh chi tiết giữa cookielocalStorage, và gợi ý lựa chọn tốt nhất:


🔒 Cookie vs. localStorage

Tiêu chí Cookie (HttpOnly) localStorage
Bảo mật trước XSS ✅ Rất an toàn nếu HttpOnly ❌ Dễ bị đánh cắp nếu XSS xảy ra
Bảo mật trước CSRF ❌ Dễ bị tấn công nếu không có CSRF protection ✅ Không tự động gửi nên tránh được CSRF
Tự động gửi khi request ✅ (được gửi trong mỗi HTTP request) ❌ Phải đính kèm token thủ công (JS)
Dễ sử dụng trong frontend ❌ Khó thao tác nếu HttpOnly ✅ Truy cập dễ dàng trong JS
Khả năng cấu hình expire ✅ Có thể đặt expires, max-age ❌ Không expire tự động
Dung lượng lưu trữ ~4KB ~5MB

Gợi ý tốt nhất (Best practice):

🔐 Dùng Cookie với flag HttpOnly, Secure, và SameSite=Strict hoặc Lax

  • Access Token: không nên lưu nếu token quá ngắn hạn hoặc không muốn tự động gửi trong mọi request → bạn có thể lưu ở memory runtime.
  • Refresh Token: lưu ở HttpOnly cookie → tránh bị truy cập bởi JS nếu có lỗ hổng XSS.

Tại sao?

  • HttpOnly giúp ngăn JavaScript truy cập token → bảo vệ khỏi XSS.
  • Secure đảm bảo chỉ gửi qua HTTPS.
  • SameSite giúp giảm thiểu rủi ro CSRF.

🔄 Mô hình đề xuất:

  1. Khi user đăng nhập → backend gửi access tokenrefresh token:

    • Access token: dùng cho các API call, lưu tạm trong memory (RAM) frontend.
    • Refresh token: lưu trong HttpOnly Secure Cookie.
  2. Khi access token hết hạn:

    • Gửi request đến /refresh-token → backend kiểm tra cookie và trả lại access token mới.

❌ Khi nào KHÔNG nên dùng localStorage?

  • Nếu ứng dụng của bạn có dữ liệu quan trọng hoặc cần bảo vệ nghiêm ngặt → KHÔNG dùng localStorage để lưu token, vì:
    • Token có thể bị đánh cắp nếu có XSS dù chỉ 1 dòng.

Flow chart: Mô hình lưu JWT an toàn trong Next.js

[User Login Form]
        |
        v
[POST /api/login]  <--- credentials (username, password)
        |
        v
[Next.js API Route xử lý login]
        |
        |--> Verify credentials
        |--> Generate Access Token (short-lived)
        |--> Generate Refresh Token (long-lived)
        |
        |--> Đặt Refresh Token vào HttpOnly Cookie
        |--> Trả Access Token trong JSON response
        |
        v
[Client nhận access token] --> Lưu trong memory (RAM, state, hoặc React context)
        |
        v
[Client gọi API protected]
        |
        |--> Đính kèm access token trong Authorization Header
        |
        v
[API xác thực access token]
        |
        v
[Trả về dữ liệu nếu token hợp lệ]

=== Khi access token hết hạn ===

[Client gửi request đến /api/refresh-token]
        |
        v
[Next.js API Route đọc refresh token từ cookie]
        |
        |--> Verify refresh token
        |--> Tạo access token mới
        |
        v
[Trả về access token mới]
        |
        v
[Client cập nhật lại access token trong memory]


✅ Tổng kết:

Trường hợp Khuyến nghị
Ứng dụng có mức bảo mật cao Cookie HttpOnly
Ứng dụng đơn giản, cần nhanh gọn Có thể dùng localStorage (rất hạn chế)
Dùng OAuth, refresh token Cookie HttpOnly cho refresh token + memory cho access token

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí