Ở 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.








Khoá học lập trình game con rắn cho trẻ em




