Giải mã JWT online: đọc header, payload, kiểm tra hạn và hiểu vì sao giải mã không phải xác minh
Công cụ tách một chuỗi JSON Web Token thành ba phần, giải mã header và payload về dạng JSON có thụt lề, hiển thị nguyên văn phần chữ ký và tự đối chiếu trường exp để cho biết token còn hạn hay đã hết. Toàn bộ xử lý chạy trên trình duyệt nên token không được gửi đi đâu.
Tính năng nổi bật
- Tách chuỗi token theo dấu chấm và báo lỗi rõ khi không đủ ba phần
- Giải mã base64url cho cả header và payload, tự xử lý hai ký tự gạch ngang và gạch dưới
- Hiển thị JSON có thụt lề bằng phông đơn cách nên dễ đọc cấu trúc lồng nhau
- Sao chép riêng phần header hoặc phần payload dưới dạng JSON đã định dạng
- Tự nhận trường exp và cho biết token còn hiệu lực hay đã hết hạn
- Quy đổi thời điểm hết hạn sang ngày giờ theo định dạng Việt Nam
- Hiển thị nguyên văn chuỗi chữ ký kèm ghi chú rõ là không thể xác minh phía trình duyệt
- Chạy hoàn toàn trên trình duyệt, token không rời khỏi máy bạn
Vì sao lúc gỡ lỗi đăng nhập, việc đầu tiên là mở token ra xem
Khi một yêu cầu bị trả về lỗi 401 hoặc 403, có rất nhiều nguyên nhân khả dĩ và phần lớn chúng lộ ra ngay trong nội dung token. Token đã hết hạn từ hôm qua vì đồng hồ máy khách sai. Trường aud trỏ về một dịch vụ khác nên máy chủ từ chối. Danh sách quyền trong payload thiếu đúng cái quyền mà điểm cuối đang yêu cầu. Trường sub là mã người dùng của môi trường thử nghiệm trong khi bạn đang gọi lên môi trường thật. Trường kid trỏ tới một khóa đã bị xoay vòng. Tất cả những thứ đó bạn thấy trong vài giây chỉ bằng cách dán token vào và đọc. Đó là lý do công cụ giải mã JWT gần như luôn là bước đầu tiên trước khi đi đọc nhật ký máy chủ, và cũng là lý do nó nên chạy tại chỗ trên trình duyệt: token đang dùng thật là thông tin nhạy cảm, ai cầm được nó thì hành động thay bạn cho tới khi nó hết hạn.
Lợi ích khi sử dụng
- Tìm ra nguyên nhân lỗi xác thực trong vài giây thay vì lần mò trong nhật ký
- Biết chính xác token hết hạn lúc nào theo giờ Việt Nam
- Sao chép payload đã định dạng để dán vào phiếu lỗi hoặc vào tài liệu
- Kiểm tra nhanh xem hệ thống có đang lỡ đặt dữ liệu nhạy cảm vào token không
- Token không rời khỏi trình duyệt nên dùng được với token của môi trường thật
Cách giải mã một JWT
- 1Sao chép token từ tiêu đề Authorization, từ cookie hoặc từ phản hồi đăng nhập; nhớ bỏ chữ Bearer và khoảng trắng ở đầu.
- 2Dán vào ô nhập, kết quả hiện ngay mà không cần bấm nút nào.
- 3Đọc header trước để biết thuật toán ký ở trường alg và mã khóa ở trường kid nếu có.
- 4Đọc payload và soi các trường exp, iat, aud, sub cùng danh sách quyền; khung màu ngay dưới payload cho biết token còn hạn hay đã hết.
- 5Nếu công cụ báo token không đúng định dạng, kiểm tra xem chuỗi có bị cắt cụt, có dính dấu ngoặc kép, hay thực chất là token dạng mã hóa năm phần chứ không phải ba phần.
Cấu trúc ba phần của một JWT
Một token gồm ba đoạn ngăn cách bởi hai dấu chấm. Đoạn thứ nhất là header, một đối tượng JSON mô tả cách token được ký, thường chứa trường alg cho thuật toán và trường typ với giá trị JWT; nhiều hệ thống thêm trường kid làm mã định danh khóa để hỗ trợ xoay vòng khóa. Đoạn thứ hai là payload, chứa các khẳng định về người dùng và về chính token. Đoạn thứ ba là chữ ký, tạo ra bằng cách ký lên chuỗi ghép của hai đoạn đầu. Cả ba đoạn đều được mã hóa base64url, tức biến thể của Base64 thay dấu cộng bằng gạch ngang, gạch chéo bằng gạch dưới và thường bỏ phần đệm dấu bằng, để chuỗi đặt được trong đường dẫn và trong tiêu đề HTTP. Điều then chốt cần nhớ là base64url chỉ là cách viết lại chứ không phải mã hóa bảo mật: ai cầm token cũng đọc được toàn bộ header và payload, đúng như những gì công cụ này vừa làm. Nếu token của bạn có năm đoạn thay vì ba, đó là dạng token được mã hóa nội dung chứ không chỉ ký, và công cụ giải mã ba phần sẽ báo lỗi định dạng.
Bảy trường chuẩn trong payload và ý nghĩa thực dụng
Chuẩn định nghĩa bảy trường đăng ký sẵn, tất cả đều không bắt buộc nhưng dùng rất phổ biến. Trường iss cho biết ai phát hành token, hữu ích khi hệ thống chấp nhận nhiều nguồn đăng nhập. Trường sub là chủ thể, thường là mã người dùng, và đây là trường bạn nên dùng làm khóa thay vì địa chỉ thư điện tử vì thư có thể đổi. Trường aud là đối tượng nhận, và máy chủ phải kiểm tra trường này, nếu không một token cấp cho dịch vụ A có thể bị dùng ở dịch vụ B. Trường exp là thời điểm hết hạn, tính bằng số giây kể từ mốc năm 1970. Trường nbf là thời điểm bắt đầu có hiệu lực, dùng khi cấp token trước cho một sự kiện trong tương lai. Trường iat là thời điểm phát hành, dùng để tính tuổi token và để buộc đăng nhập lại khi đổi mật khẩu. Trường jti là mã định danh duy nhất của token, cần thiết nếu bạn muốn dựng danh sách chặn. Ngoài bảy trường này, hệ thống nào cũng thêm các trường riêng như vai trò, quyền hạn, mã tổ chức, và đó là phần bạn cần soi kỹ khi gỡ lỗi phân quyền.
Giải mã không phải xác minh, và đây là điều quan trọng nhất
Công cụ này đọc được nội dung token vì nội dung vốn công khai, nhưng nó không thể và không nên khẳng định token là hợp lệ. Việc xác minh đòi hỏi tính lại chữ ký từ hai đoạn đầu bằng đúng khóa mà máy chủ dùng: với các thuật toán đối xứng như HS256 thì cần khóa bí mật, với các thuật toán bất đối xứng như RS256 hay ES256 thì cần khóa công khai tương ứng. Đưa khóa bí mật vào một trang web là điều không bao giờ nên làm, nên công cụ chỉ hiển thị nguyên văn chữ ký và dừng ở đó. Hệ quả về bảo mật cần nhớ khi tự viết máy chủ: phải kiểm tra chữ ký trước khi tin bất cứ trường nào trong payload, và phải cố định thuật toán chấp nhận thay vì đọc trường alg trong header rồi làm theo. Hai lỗ hổng kinh điển đều xuất phát từ chỗ này: token khai alg là none khiến thư viện bỏ qua bước kiểm tra chữ ký, và token khai HS256 trong khi máy chủ dùng RS256 khiến khóa công khai bị dùng nhầm làm khóa bí mật. Thư viện hiện đại đã chặn cả hai, nhưng chỉ khi bạn cấu hình đúng.
Đừng đặt gì vào payload và vì sao token không thu hồi được
Vì payload ai cũng đọc được, đừng đặt vào đó số căn cước, số điện thoại đầy đủ, địa chỉ nhà, thông tin sức khỏe, hay bất cứ dữ liệu cá nhân nào không cần thiết cho việc phân quyền. Cũng đừng đặt mật khẩu hay khóa nội bộ, kể cả ở dạng đã mã hóa. Lý do thứ hai để giữ payload gọn là kích thước: token đi kèm mọi yêu cầu trong tiêu đề Authorization, mà nhiều máy chủ giới hạn tổng kích thước tiêu đề quanh 8 kilôbyte, còn một cookie thì giới hạn khoảng 4 kilôbyte. Nhét cả danh sách quyền chi tiết vào token là cách nhanh nhất để gặp lỗi tiêu đề quá lớn ở môi trường thật mà môi trường thử nghiệm không phát hiện. Vấn đề thứ ba là token đã cấp thì không thu hồi được, vì máy chủ không lưu trạng thái của nó; nếu người dùng bị khóa tài khoản lúc 10 giờ mà token còn hạn tới 12 giờ thì trong hai tiếng đó họ vẫn truy cập được. Cách xử lý thông dụng là đặt hạn ngắn cho token truy cập, thường 5 tới 15 phút, dùng token làm mới có hạn dài hơn và lưu trạng thái ở máy chủ, cộng thêm danh sách chặn theo trường jti cho các trường hợp khẩn.
Những lỗi hay gặp khi gỡ rối bằng công cụ giải mã
Lỗi số một là nhầm đơn vị của exp và iat: chúng tính bằng giây, còn hàm lấy thời gian hiện tại trong JavaScript trả về mili giây, nên phải nhân với 1000 trước khi so sánh. Nhầm chỗ này khiến mọi token trông như đã hết hạn từ năm 1970. Lỗi số hai là lệch đồng hồ giữa máy cấp và máy kiểm tra: chỉ cần lệch vài chục giây là token vừa cấp đã bị coi là chưa đến hạn hiệu lực; phần lớn thư viện cho phép khai báo một biên độ chấp nhận vài chục giây. Lỗi số ba là dán nhầm cả tiền tố Bearer hoặc cả dấu ngoặc kép khi sao chép từ tệp JSON, khiến công cụ báo sai định dạng. Lỗi số bốn là token bị cắt cụt do vượt giới hạn kích thước của cookie hoặc của một trường trong cơ sở dữ liệu, dấu hiệu là đoạn chữ ký ngắn bất thường. Lỗi số năm là riêng của công cụ này: nếu payload chứa tiếng Việt có dấu, ví dụ tên người dùng, phần chữ có dấu có thể hiển thị thành ký tự lạ do cách giải mã byte, còn bản thân token vẫn nguyên vẹn. Khi gặp trường hợp đó, hãy tin vào giá trị do máy chủ đọc ra chứ đừng kết luận token hỏng.
Câu hỏi thường gặp (FAQ)
JWT gồm những phần nào?
Ba phần ngăn cách bởi hai dấu chấm: header mô tả thuật toán ký, payload chứa các khẳng định về người dùng và về token, và chữ ký tạo từ hai phần đầu. Cả ba đều mã hóa base64url. Nếu token của bạn có năm phần thì đó là dạng token mã hóa nội dung, không phải dạng ba phần này.
Vì sao ai cũng đọc được nội dung JWT của tôi?
Vì header và payload chỉ được mã hóa base64url, tức cách viết lại chứ không phải mã hóa bảo mật. Thứ bảo vệ token là chữ ký ở phần thứ ba, nó ngăn người khác sửa nội dung chứ không ngăn đọc. Vì vậy đừng đặt dữ liệu nhạy cảm vào payload.
Công cụ có xác minh được chữ ký không?
Không, và cố tình không. Xác minh cần khóa bí mật với thuật toán đối xứng hoặc khóa công khai với thuật toán bất đối xứng, mà đưa khóa bí mật vào một trang web là điều không nên làm. Công cụ chỉ hiển thị nguyên văn chữ ký để bạn đối chiếu bằng mắt.
Trường exp tính theo đơn vị gì?
Theo số giây kể từ mốc 00 giờ ngày 1 tháng 1 năm 1970 giờ UTC. Đây là chỗ hay nhầm nhất khi lập trình bằng JavaScript, vì hàm lấy thời gian hiện tại trả về mili giây, nên phải nhân exp với 1000 trước khi so sánh, nếu không mọi token đều trông như đã hết hạn.
Trường aud dùng để làm gì và vì sao phải kiểm tra?
Nó cho biết token được cấp cho dịch vụ nào. Nếu máy chủ không kiểm tra trường này, một token hợp lệ do cùng nhà phát hành cấp cho dịch vụ A có thể bị dùng để truy cập dịch vụ B. Đây là lỗi cấu hình khá phổ biến trong hệ thống nhiều dịch vụ dùng chung một nhà cung cấp danh tính.
Thu hồi một JWT đã cấp bằng cách nào?
Về bản chất là không thu hồi được, vì máy chủ không lưu trạng thái của token. Cách xử lý thông dụng là đặt hạn ngắn cho token truy cập, thường 5 tới 15 phút, dùng token làm mới có lưu trạng thái ở máy chủ, và lập danh sách chặn theo trường jti cho trường hợp khẩn cấp.
Nên đặt hạn cho token là bao lâu?
Token truy cập nên ngắn, phổ biến là 5 tới 15 phút, để giảm thiệt hại nếu bị lộ. Token làm mới có thể dài hơn nhiều nhưng phải lưu ở máy chủ để thu hồi được, và nên xoay vòng mỗi lần dùng để phát hiện trường hợp token bị đánh cắp và dùng lại.
Lỗ hổng alg none là gì?
Là trường hợp kẻ tấn công sửa header thành thuật toán none, và thư viện cũ sẽ hiểu là token không cần chữ ký nên bỏ qua bước kiểm tra. Cách phòng là cố định danh sách thuật toán được chấp nhận ở phía máy chủ thay vì đọc trường alg trong header rồi làm theo.
Công cụ báo token không đúng định dạng, phải kiểm tra gì?
Kiểm tra bốn thứ: chuỗi có bị cắt cụt không, có dính tiền tố Bearer hay dấu ngoặc kép khi sao chép không, có đúng ba đoạn ngăn cách bởi dấu chấm không, và có phải thực chất là token dạng năm đoạn được mã hóa nội dung hay không.
Vì sao tiếng Việt trong payload hiển thị thành ký tự lạ?
Do cách giải mã byte của công cụ chưa chuyển tiếp sang UTF-8 ở bước cuối, nên chữ có dấu hiện thành ký tự chồng chéo. Bản thân token vẫn nguyên vẹn và máy chủ vẫn đọc đúng giá trị. Khi gặp trường hợp này, hãy tin vào giá trị máy chủ đọc ra chứ đừng kết luận token hỏng.
Token của tôi có bị gửi lên máy chủ khi dán vào đây không?
Không. Việc tách chuỗi, giải mã base64url và phân tích JSON đều chạy bằng JavaScript trên trình duyệt, không có yêu cầu mạng nào được tạo ra. Bạn kiểm chứng được bằng tab mạng trong công cụ dành cho nhà phát triển, hoặc bằng cách ngắt mạng rồi dán token vào.
Nên lưu JWT ở cookie hay ở localStorage?
Cookie đặt cờ HttpOnly và SameSite an toàn hơn trước tấn công chèn mã, vì mã JavaScript không đọc được cookie đó, nhưng cần chống giả mạo yêu cầu liên trang. Lưu ở localStorage tiện hơn nhưng bất kỳ đoạn mã lạ nào chạy trên trang cũng lấy được token. Với ứng dụng cần bảo mật cao, cookie HttpOnly là lựa chọn thường được khuyến nghị.
Từ khóa liên quan
- giải mã jwt online
- jwt decoder
- json web token là gì
- đọc payload jwt
- kiểm tra jwt hết hạn
- jwt exp iat là gì
- base64url trong jwt
- xác minh chữ ký jwt
- jwt alg none lỗ hổng
- hs256 rs256 khác nhau
- claim chuẩn rfc 7519
- thu hồi jwt
- refresh token là gì
- jwt lưu ở cookie hay localstorage
- lỗi 401 unauthorized jwt
- jwt aud audience
- kid trong jwt header
- token quá dài lỗi header
- gỡ lỗi đăng nhập api
- công cụ decode jwt miễn phí
