Ở bài JWT & Token Authentication, ta đã biết JWT được sử dụng để xác thực user sau khi đăng nhập:

Login
  ↓
Server xác thực username/password
  ↓
Access Token + Refresh Token
  ↓
Client lưu token
  ↓
Gửi Access Token trong mỗi request

Ví dụ:

GET /api/profile
Authorization: Bearer <access-token>

Server nhận token, verify token rồi xác định user đang thực hiện request.

Từ đây có một câu hỏi rất quan trọng về security Nếu attacker lấy được JWT thì họ có thể sửa Payload, ví dụ đổi userId từ 10 thành 20 để giả làm user khác không?

Để hiểu điều này, cần hiểu rõ Payload và Signature hoạt động như thế nào.

1. JWT gồm những gì?

như bài trước jwt gồm 3 phần header .payload .signature

Ví dụ:

eyJhbGciOiJIUzI1NiJ9 (header)
.
eyJ1c2VyX2lkIjoxMCwiZXhwIjoxNzk5OTk5OTk5fQ (payload)
.
abc123... (signature)

Ba phần này có vai trò khác nhau:

Header
→ JWT sử dụng thuật toán nào

Payload
→ chứa các claims như userId, role, exp...

Signature
→ dùng để kiểm tra token có bị thay đổi hay không

Ví dụ Payload có thể là:

{
    "userId": 10,
    "role": "user",
    "exp": 1799999999
}

2. Payload của JWT có được mã hóa không?

Thông thường, JWT không encrypt Payload Payload thường chỉ được encode. Điều này có nghĩa là nếu attacker có JWT, họ có thể decode Payload để xem nội dung.

Ví dụ:

{
    "userId": 10,
    "role": "user"
}

Hacker có thể biết:

userId = 10
role = user

Nhưng việc Có thể đọc Payload không có nghĩa là có thể sửa Payload rồi tạo ra một JWT hợp lệ.

Đây là điểm quan trọng nhất của phần này.

3. Hacker có thể sửa userId không?

Về mặt kỹ thuật, attacker có thể thay đổi phần Payload.

Ví dụ token ban đầu:

{
    "userId": 10,
    "role": "user"
}

Hacker sửa thành:

{
    "userId": 20,
    "role": "user"
}

hoặc thâm chí có thể sửa cả role

{
    "userId": 20,
    "role": "admin"
}
tuy nhiên payload có thể sửa nhưng phần quan trọng của jwt nằm ở phần signature.

4. Signature dùng để làm gì?

Khi server tạo JWT, server sẽ tạo Signature dựa trên Header + Payload và secret/private key.

Có thể hình dung:

Header + Payload
       +
    Secret Key
       ↓
    Signature

Ví dụ ban đầu:

Payload:

{
    "userId": 10,
    "role": "user"
}

Server tạo:

Signature A

Sau đó JWT trở thành:

Header.Payload.Signature-A

Khi client gửi JWT trở lại server, server sẽ verify Signature.

Nếu Hacker đổi phần payload thì signature sẽ báo sai ngay vì không khớp với cái payload ban đầu đã băm ra.

Giả sử JWT ban đầu:

{
    "userId": 10,
    "role": "user"
}

và có:

Signature A

Attacker sửa Payload:

{
    "userId": 20,
    "role": "user"
}

nhưng vẫn giữ Signature A.

Token lúc này về mặt nội dung là:

Header.Payload-mới.Signature-A

Server sẽ tính lại Signature dựa trên Payload mới:

Header + Payload-mới
        +
    Secret Key
        ↓
    Signature B

Kết quả:

Signature A ≠ Signature B

5. Tại sao attacker không tạo Signature mới?

đúng vậy, tại sao về kỹ thuật có thể đổi payload thì sao không đổi cái singnature cho khớp.

Hacker có thể biết:

Header
Payload

nhưng không có:

Secret Key

đây mới là cái quan trọng Secret Key.

Nếu server sử dụng một secret để ký JWT:

JWT_SECRET = ...

thì chỉ server mới có secret đó.

Muốn tạo Signature hợp lệ cho Payload mới, hacker cần có key tương ứng.

Có thể hình dung:

Hacker

Header
   +
Payload mới
   ↓
??? Signature

Không có secret/private key:

→ Không tạo được Signature hợp lệ

Vì vậy hacker có thể sửa Payload, nhưng không thể biến Payload đã sửa thành một JWT hợp lệ nếu không có key cần thiết để tạo Signature.

6. Nhưng JWT vẫn có thể bị khai thác nếu server triển khai sai

JWT có Signature không có nghĩa là application tự động an toàn.

Server vẫn có thể mắc lỗi.

Ví dụ nguy hiểm nhất là không verify Signature đúng cách.

Nếu application làm:

JWT
 ↓
Decode Payload
 ↓
Lấy userId
 ↓
Tin luôn

thì hacker có thể thay đổi Payload mà server không phát hiện.

Một lỗi khác là:

Secret Key bị lộ

Nếu hacker có được secret/private key dùng để ký token, họ có thể tạo token mới với claims khác rồi ký token đó.

Ví dụ về mặt khái niệm:

{
    "userId": 20,
    "role": "admin"
}

Sau đó tạo Signature hợp lệ bằng key bị lộ.

Server sẽ thấy:

Signature hợp lệ

và nếu application tin các claims đó, attacker có thể đạt được quyền không được phép.

Vì vậy JWT Secret hoặc private key phải được bảo vệ như một credential cực kỳ nhạy cảm Không commit vào Git repository, không đưa lên frontend và không log ra console. và các key nhạy cảm thì sẽ được đặc trong file .env riêng biệt để tránh push lên git.

Chốt lại:

JWT dùng Signature để đảm bảo Payload không bị thay đổi một cách âm thầm. Nếu hacker sửa Payload, Signature sẽ không còn khớp và token sẽ bị từ chối. Tuy nhiên, Signature không bảo vệ JWT khỏi việc bị đánh cắp. Nếu hacker lấy được một JWT hợp lệ, họ có thể sử dụng chính token đó cho đến khi token hết hạn hoặc bị hệ thống vô hiệu hóa. vì vậy để tránh tình trạng xấu xảy ra có kết hợp nhiều lớp bảo vệ sử dụng https để bảo vệ token truyền qua mạng vì HTTPS là URL đã được mã hóa an toàn. dùng access token có thời gian hiệu lực ngắn nhất có thể. bảo vệ refesh token cẩn thận luôn verify chữ ký (signature) và kiểm tra expiration. thực hiện authorization để đảm bảo user chỉ được sử dụng và truy cập các api hay tài nguyên phù hợp. luôn bảo vệ nghiêm ngặt scret key và thông tin nhạy cảm.

Bài viết khác

Series 7 — Web Quality – Engineering :Testing – Unit Testing, Integration Testing, Web Performance – Core Web Vitals, Code Splitting, Lazy Loading

Series 7 — Web Quality – Engineering Bài 3: Testing – Unit Testing, Integration Testing và End-to-End Testing trong ứng dụng web 1. Vì sao ứng dụng web cần Testing? Trong quá trình phát triển Frontend, chúng ta thường kiểm tra ứng dụng bằng cách chạy website trên trình duyệt, nhấn vào các nút, nhập […]

Series 7 — Web Quality – Engineering : Authentication & Authorization

Series 7 — Web Quality – Engineering Bài 1: Authentication & Authorization – Xác thực và phân quyền trong ứng dụng web 1. Mở đầu Khi xây dựng một ứng dụng web có chức năng đăng nhập, chúng ta thường nghĩ rằng chỉ cần tạo biểu mẫu nhập email, mật khẩu và kiểm tra thông […]

Series 6 – Next.js Advanced – Production: Next.js Build & Deployment

Series 6 – Next.js Advanced & Production Bài 5: Next.js Build & Deployment – Từ mã nguồn đến môi trường Production 1. Mở đầu Trong quá trình phát triển một ứng dụng web, việc chạy thành công trên máy tính cá nhân chưa có nghĩa là ứng dụng đã sẵn sàng để đưa đến người […]

Series 6 – Next.js Advanced – Production: Next.js Internationalized Routing Next.js Static Export

Series 6 – Next.js Advanced & Production   Bài 3: Next.js Internationalized Routing – Tổ chức URL cho website đa ngôn ngữ 1. Mở đầu Sau khi xây dựng cơ chế dịch nội dung và định dạng theo locale, ứng dụng cần một cách để người dùng truy cập đúng phiên bản ngôn ngữ. Ví […]

Series 6 – Next.js Advanced & Production: Metadata & SEO, Internationalization (i18n) & Localization (l10n)

Series 6 – Next.js Advanced & Production Bài 1: Metadata & SEO trong Next.js – Tối ưu thông tin và khả năng hiển thị trên công cụ tìm kiếm 1. Mở đầu Khi xây dựng một website, việc hoàn thiện giao diện và chức năng mới chỉ là một phần của quá trình phát triển. […]

Series 5 – Next.js Fundamentals: CSR, SSR, SSG, ISR và cách lựa chọn

Series 5 – Next.js Fundamentals   Bài 7 : CSR, SSR, SSG và ISR – Các chiến lược Rendering trong Next.js 1. Mở đầu Khi xây dựng một website bằng React, chúng ta thường tập trung vào việc tạo component, quản lý state và hiển thị giao diện trên trình duyệt. Tuy nhiên, khi ứng dụng […]

Leave a Reply

Your email address will not be published. Required fields are marked *