Mỗi khi người dùng đăng nhập vào một ứng dụng SaaS, hệ thống sẽ tạo ra một
auth token
và gửi về trình duyệt hoặc ứng dụng di động của họ. Token đó mang theo một chiếc đồng hồ ẩn bên trong. Trường
JWT expiration, được lưu dưới dạng Unix timestamp thuần túy, cho mọi server biết chính xác thời điểm nào thì ngừng tin tưởng credential đó. Chỉ cần sai lệch vài giây, người dùng có thể bị đăng xuất sớm hơn dự kiến, hoặc tệ hơn, phiên làm việc của họ tồn tại lâu hơn mức chính sách bảo mật cho phép. Hiểu rõ cách các claim trong
JSON web token
hoạt động, đặc biệt là
exp
và
iat
, là một trong những việc thiết thực nhất mà đội ngũ SaaS có thể làm để tăng cường bảo mật xác thực mà không gây phiền toái cho người dùng.
Điểm chính cần nhớ:
-
Các claim
expvàiattrong JWT JSON web token luôn là Unix timestamp tính bằng giây nguyên, không phải millisecond. - Độ lệch đồng hồ giữa các server có thể âm thầm làm mất hiệu lực token hoặc kéo dài phiên làm việc vượt quá chính sách - cửa sổ dung sai 60 giây là chuẩn công nghiệp được khuyến nghị.
- Đặt token expiry quá dài làm tăng rủi ro bảo mật; đặt quá ngắn làm hỏng trải nghiệm người dùng. Có một công thức cụ thể giúp bạn chọn giá trị phù hợp.
- Bạn có thể giải mã và xác minh bất kỳ timestamp nào trong JSON web token bằng công cụ chuyển đổi Unix epoch, không cần thư viện nào cả.
Mục lục
JWT là gì và tại sao timestamp lại nằm bên trong token
JSON web token là một credential nhỏ gọn, an toàn với URL, gồm ba phần được mã hóa Base64 và ngăn cách nhau bằng dấu chấm: header, payload và signature. Payload là nơi chứa dữ liệu nhạy cảm với thời gian. Vì JWT hoạt động theo cơ chế stateless, server không cần tra cứu phiên làm việc trong cơ sở dữ liệu để xác thực. Thay vào đó, server đọc các claim được nhúng sẵn trong payload và tin tưởng vào chữ ký mật mã. Thiết kế này nhanh và có khả năng mở rộng tốt, nhưng đi kèm với một ràng buộc thực tế: một khi token đã được phát hành, server không thể "xóa" nó. Cách duy nhất để giới hạn vòng đời của token là nhúng trực tiếp timestamp hết hạn vào bên trong token đó.
Đó là lý do tại sao thời gian, cụ thể là Unix epoch time, đóng vai trò trung tâm trong bảo mật JWT. Đặc tả RFC 7519 định nghĩa JWT yêu cầu các claim liên quan đến thời gian phải được biểu diễn dưới dạng giá trị "NumericDate", tức là số giây tính từ ngày 1 tháng 1 năm 1970 UTC. Không có múi giờ. Không có định dạng locale. Chỉ là một số nguyên mà bất kỳ server nào trên thế giới đều có thể so sánh với đồng hồ của chính nó.
Giải thích chi tiết claim
exp
và
iat
Đặc tả JWT định nghĩa nhiều claim đã được đăng ký. Hai claim quan trọng nhất cho việc quản lý vòng đời token là:
-
exp(Expiration Time): Timestamp sau thời điểm này token không được chấp nhận nữa. Server bắt buộc phải từ chối mọi token mà thời gian hiện tại bằng hoặc lớn hơn giá trị này. Đây là cơ chế cốt lõi của JWT expiration. -
iat(Issued At): Timestamp tại thời điểm token được tạo ra. Claim iat không được thực thi mặc định, nhưng cực kỳ hữu ích. Nó cho phép bạn tính tuổi của token, áp dụng chính sách tuổi tối đa độc lập vớiexp, và phát hiện các token được phát hành từ quá lâu trong quá khứ một cách đáng ngờ.
Một claim thứ ba,
nbf
(Not Before), xác định thời điểm sớm nhất token có hiệu lực. Claim này ít được dùng hơn nhưng vẫn theo cùng định dạng Unix timestamp.
Cả ba giá trị đều là số nguyên. Nếu hệ thống của bạn tạo ra chúng bằng đơn vị millisecond (lỗi phổ biến khi dùng
Date.now()
trong JavaScript), con số thu được sẽ lớn hơn khoảng 1.000 lần so với mong đợi. Server kiểm tra
exp
theo epoch giây hiện tại sẽ thấy token dường như hết hạn vào năm 33.658 và sẽ không bao giờ từ chối nó. Đây là một lỗi thực tế trong môi trường production đã ảnh hưởng đến nhiều đội ngũ SaaS.
Ví dụ thực tế: Giải mã timestamp trong token
Giả sử dịch vụ xác thực của bạn phát hành JWT payload sau khi người dùng đăng nhập lúc 10:00 SA UTC ngày 1 tháng 7 năm 2025:
{
"sub": "user_8821",
"iat": 1751364000,
"exp": 1751367600,
"role": "admin"
}
Hãy cùng phân tích ý nghĩa của các con số đó:
| Claim | Unix Timestamp | Dạng đọc được (UTC) | Ý nghĩa |
|---|---|---|---|
iat
|
1751364000 | 2025-07-01 10:00:00 | Token được phát hành tại thời điểm này |
exp
|
1751367600 | 2025-07-01 11:00:00 | Token hết hạn sau đúng 1 giờ |
Hiệu số là đúng 3.600 giây, tương đương một giờ. Bất kỳ server nào nhận token này sau 11:00:00 UTC đều phải từ chối nó. Để xác minh thủ công, bạn lấy
exp
trừ
iat
: 1751367600 - 1751364000 = 3600 giây. Bạn có thể xác nhận giá trị đọc được tương ứng của bất kỳ con số nào trong số này ngay lập tức bằng công cụ chuyển đổi Unix timestamp - đây chính xác là kiểu kiểm tra nhanh giúp tránh lỗi millisecond-vs-giây đã đề cập ở trên.
Để hiểu sâu hơn về cách cơ sở dữ liệu nên lưu trữ các giá trị này, hãy xem hướng dẫn của chúng tôi về
Unix timestamp trong cơ sở dữ liệu, vì cùng một định dạng số nguyên áp dụng cho dù bạn đang lưu
exp
trong token hay trong bảng audit log.
Clock skew: Kẻ thù thầm lặng của token
Đây là một ràng buộc thực tế thường khiến các đội ngũ bị bất ngờ. Trong hệ thống phân tán, server xác thực và server API là hai máy khác nhau. Đồng hồ hệ thống của chúng được đồng bộ qua NTP, nhưng không bao giờ hoàn toàn khớp nhau. Sai lệch từ 30 đến 90 giây là chuyện bình thường trong môi trường cloud.
Hãy xét tình huống này: một token có
exp = 1751367600
được xác thực bởi API server có đồng hồ đang chỉ 1751367610, chỉ 10 giây sau thời điểm hết hạn. Token bị từ chối. Người dùng nhận lỗi 401. Từ góc nhìn của họ, họ vừa đăng nhập xong thì ứng dụng đã bị lỗi.
Giải pháp chuẩn là tích hợp dung sai clock skew vào logic xác thực của bạn. Hầu hết các thư viện JWT đều hỗ trợ tham số leeway. Giá trị 60 giây được chấp nhận rộng rãi và được tham chiếu trong đặc tả OpenID Connect Core. Hãy thiết lập nó, ghi lại tài liệu, và đảm bảo mọi dịch vụ trong hệ thống đều dùng cùng một giá trị.
Quy tắc thực tiễn:
Thêm leeway 60 giây vào việc xác thực
exp
. Đừng bao giờ thêm leeway vào kiểm tra
iat
, vì điều đó sẽ cho phép chấp nhận token được phát hành trong tương lai - đây là dấu hiệu cảnh báo của replay attack.
Chọn thời gian hết hạn token phù hợp cho sản phẩm SaaS
Giá trị token expiry phù hợp phụ thuộc vào mức độ nhạy cảm của ứng dụng và hành vi phiên làm việc dự kiến. Dưới đây là một khung thực tế:
- Ứng dụng độ nhạy cảm cao (ngân hàng, y tế, trang quản trị): 15 đến 30 phút cho access token. Dùng refresh token để tự động gia hạn phiên làm việc.
- Ứng dụng SaaS thông thường (quản lý dự án, CRM, phân tích): 1 đến 8 giờ. Khớp với độ dài phiên làm việc điển hình trong ngày.
- API ít rủi ro hoặc chỉ đọc: Lên đến 24 giờ, nhưng kết hợp với token rotation cho các thao tác nhạy cảm.
- Service token cho giao tiếp máy-máy: Có thể dài hơn (ngày hoặc tuần), nhưng nên được giới hạn phạm vi chặt chẽ và xoay vòng theo lịch định kỳ.
Công thức hữu ích để tính giá trị
exp
tại thời điểm phát hành:
// Node.js example
const iat = Math.floor(Date.now() / 1000); // current time in seconds
const ttl = 3600; // time-to-live: 1 hour in seconds
const exp = iat + ttl;
const payload = {
sub: userId,
iat: iat,
exp: exp
};
Chú ý phép chia tường minh cho 1000 để chuyển đổi từ millisecond sang giây. Dòng code đơn giản này giúp ngăn chặn lỗi JWT timestamp phổ biến nhất trong các ứng dụng JavaScript.
Các bước triển khai JWT expiration an toàn
Dưới đây là danh sách kiểm tra cụ thể bạn có thể áp dụng ngay cho bất kỳ hệ thống xác thực SaaS nào:
-
Luôn bao gồm cả
iatlẫnexp. Claimiatvề mặt kỹ thuật là tùy chọn, nhưng nó cung cấp audit trail và cho phép thực thi chính sách tuổi tối đa độc lập với expiry. -
Xác minh định dạng timestamp trước khi triển khai.
Giải mã token và kiểm tra rằng
explà số nguyên 10 chữ số. Nếu là 13 chữ số nghĩa là đã bị dính đơn vị millisecond. - Đặt leeway clock skew 60 giây trong middleware xác thực. Áp dụng nhất quán trên mọi dịch vụ tiêu thụ auth token.
- Dùng access token ngắn hạn kết hợp refresh token. Access token 15 phút kết hợp với refresh token 7 ngày an toàn hơn nhiều so với một access token duy nhất 7 ngày, vì refresh token có thể bị thu hồi phía server.
-
Ghi log giá trị
iattrên mỗi yêu cầu đã xác thực. Điều này cho phép bạn phát hiện các bất thường, chẳng hạn như cùng một token được sử dụng đồng thời từ hai khu vực địa lý khác nhau. -
Kiểm thử expiry trong môi trường staging với thời gian tăng tốc.
Giả lập đồng hồ nhảy qua giá trị
expvà xác nhận ứng dụng xử lý lỗi 401 một cách ổn thỏa thay vì bị crash hoặc lặp vô hạn.
Nếu bạn cần nhanh chóng chuyển đổi giá trị
exp
thô từ token sang dạng ngày đọc được, hoặc xác minh timestamp cần đặt cho một khoảng thời gian nhất định,
công cụ chuyển đổi epoch trên trang chủ
của chúng tôi xử lý cả hai chiều ngay lập tức, không cần viết code.
Kết luận
JWT expiration không phải là khái niệm phức tạp, nhưng đây là lĩnh vực mà những sai lầm nhỏ tạo ra lỗ hổng bảo mật lớn. Các claim
exp
và
iat
chỉ là các số nguyên - Unix timestamp tính bằng giây từ epoch. Sự đơn giản đó chính là điểm mạnh của chúng: mọi server, mọi ngôn ngữ lập trình và mọi nền tảng đều có thể so sánh hai con số mà không có sự mơ hồ nào. Kỹ năng thực sự nằm ở việc áp dụng chúng đúng cách - chọn thời lượng
token expiry
hợp lý, xử lý clock skew bằng cửa sổ dung sai, và phát hiện lỗi millisecond-vs-giây trước khi đưa lên production. Xây dựng những thói quen này vào pipeline xác thực và triển khai
JSON web token
của bạn sẽ vừa an toàn vừa dễ bảo trì.
Xác minh JWT timestamp ngay lập tức - Không cần viết code
Dán bất kỳ Unix timestamp nào từ JWT payload và chuyển đổi sang dạng ngày đọc được chỉ với một cú nhấp. Phát hiện lỗi millisecond-vs-giây trước khi đưa lên production.
Dùng thử công cụ miễn phí →
exp
(Expiration Time) là Unix timestamp sau thời điểm đó token không còn hợp lệ và phải bị từ chối.
iat
(Issued At) là timestamp khi token được tạo ra. Cả hai đều là số nguyên tính bằng giây. Claim
iat
là tùy chọn nhưng hữu ích cho việc kiểm toán và thực thi chính sách tuổi token tối đa.
Unix timestamp là số nguyên độc lập với múi giờ, không gây nhầm lẫn trên mọi server và khu vực. Chuỗi ngày tháng như "2025-07-01T10:00:00" có thể bị hiểu sai dựa trên cài đặt locale hoặc múi giờ. Phép so sánh số nguyên cũng nhanh hơn và ít lỗi hơn so với phân tích cú pháp chuỗi trong các hệ thống xác thực có thông lượng cao.
Token tồn tại lâu vẫn hợp lệ ngay cả khi tài khoản người dùng bị xâm phạm hoặc quyền hạn của họ thay đổi. Do JWT hoạt động theo cơ chế stateless, server không thể thu hồi chúng trong suốt vòng đời. Nếu kẻ tấn công đánh cắp token có thời hạn 30 ngày, họ có 30 ngày truy cập. Kết hợp cửa sổ expiry ngắn với refresh token giúp giảm đáng kể cửa sổ rủi ro này.
Trong JavaScript, luôn dùng
Math.floor(Date.now() / 1000)
khi tạo giá trị
iat
hoặc
exp
. Hàm
Date.now()
trả về millisecond. Chia cho 1000 sẽ chuyển đổi sang số nguyên tính bằng giây theo yêu cầu của đặc tả JWT. Kiểm tra bằng cách xác nhận timestamp của bạn là số 10 chữ số, không phải 13 chữ số.
Clock skew là sự chênh lệch thời gian nhỏ giữa đồng hồ hệ thống của hai server trong hệ thống phân tán. Chỉ cần sai lệch 30 giây cũng có thể khiến token hợp lệ bị từ chối nếu đồng hồ của server xác thực chạy nhanh hơn một chút. Giải pháp chuẩn là cấu hình leeway 60 giây trong thư viện xác thực JWT để hấp thụ độ trôi NTP thông thường.