JSON Web Token (hay còn gọi là JWT) là mã thông báo nhỏ gọn, an toàn với URL được sử dụng để truyền thông tin một cách an toàn giữa các đối tượng JSON. Bên cạnh đó, chúng còn được sử dụng để xác thực và trao đổi. Vậy JSON Web Token được sử dụng như thế nào và có chức năng gì trong lập trình web?
Đọc bài viết sau đây để tìm hiểu chi tiết hơn về:
- Tổng quan JSON Web Token về các yếu tố như định nghĩa, cách hoạt động và những điểm mạnh, còn hạn chế
- Cấu trúc sử dụng cơ bản của JSON Web Token
Đọc thêm: JSON là gì? Các loại dữ liệu JSON là gì và áp dụng thế nào?
Định nghĩa về JSON Web Token
JSON Web Token (hay còn gọi là JWT) là một tiêu chuẩn mã nguồn mở (open industry standard) được sử dụng để chia sẻ thông tin an toàn, khép kín giữa hai thực thể, thường là máy khách (chẳng hạn như frontend của ứng dụng) và máy chủ (backend của ứng dụng).
JSON Web Token chứa các đối tượng JSON có thông tin cần được chia sẻ. Mỗi JWT sử dụng chữ ký số (digital signature). Các bên sẽ sử dụng mật mã khóa đối xứng (cùng với HMAC) hoặc dùng cặp khóa công khai/riêng tư (public/private key pairs) để thực hiện ký số (signed).
Ví dụ như khi bạn đăng nhập Google, Google sẽ phát hành JWT chứa các xác nhận quyền sở hữu (claims) hoặc JSON payload như sau:
{ "iss": "https://accounts.google.com", "azp": "1234987819200.apps.googleusercontent.com", "aud": "1234987819200.apps.googleusercontent.com", "sub": "10769150350006150715113082367", "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q", "email": "jsmith@example.com", "email_verified": "true", "iat": 1353601026, "exp": 1353604926, "nonce": "0394852-3190485-2490358", "hd": "example.com" }
Bằng cách sử dụng đoạn mã trên, ứng dụng sẽ sử dụng tính năng đăng nhập bằng Google để biết chính xác người dùng cuối cùng là ai.
JSON Web Token hoạt động như thế nào?
Tạo JSON Payload
Bước đầu tiên trong quá trình hoạt động của JWT chính là tạo một JSON payload và sau đó tiến hành xác minh nó:
{ "userId": "abcd123", "expiry": 1646635611301 }
Tạo khóa ký JWT và quyết định thuật toán
Sau đó, bạn cần một khóa ký và một thuật toán để sử dụng. Chúng tôi có thể tạo khóa ký bằng cách sử dụng bất kỳ nguồn ngẫu nhiên an toàn nào.Với ví dụ này, bạn có sử dụng các khóa ký và thuật toán như sau:
Khóa ký:
NTNv7j0TuYARvmNMmWXo6fKvM4o6nv/aUi9ryX38ZH+L1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiT/qJACs1J0apruOOJCg/gOtkjB4c=
Thuật toán:
HMAC + SHA256 hay còn gọi là HS256.
Tạo Header
Điều này chứa thông tin về thuật nào được sử dụng. Giống như payload, đây cũng là JSON và sẽ được thêm vào phần đầu của JWT.
{ "typ": "JWT", "alg": "HS256" }
Tạo chữ ký
Đầu tiên, xóa tất cả khoảng trắng khỏi payload JSON và sau đó mã hóa base64 để cung cấp. Có thể dán chuỗi này vào bộ giải mã base64 trực tuyến để truy xuất JSON:
eyJ1c2VySWQiOiJhYmNkMTIzIiwiZXhwaXJ5IjoxNjQ2NjM1NjExMzAxfQ
Tương tự, xóa khoảng trắng khỏi header JSON và mã hóa base64 với chuỗi
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Sau đó, nối cả hai chuỗi cơ sở
<header>.<payload>, eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzIiwiZXhwaXJ5IjoxNjQ2NjM1NjExMzAxfQ.
Đoạn mã ví dụ cho chuỗi nối trên như sau:
Base64URLSafe( HMACSHA256("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzIiwiZXhwaXJ5IjoxNjQ2NjM1NjExMzAxfQ", "NTNv7j0TuYARvmNMmWXo6fKvM4o6nv/aUi9ryX38ZH+L1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiT/qJACs1J0apruOOJCg/gOtkjB4c=") )
Tạo JWT
Cuối cùng, nối thêm chữ ký được tạo như <header>.<payload>.<signature> để tạo JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzIiwiZXhwaXJ5IjoxNjQ2NjM1NjExMzAxfQ.3Thp81rDFrKXr3WrY1MyMnNK8kKoZBX9lg-JwFznR-M
Xác minh JWT
Máy chủ xác thực sẽ gửi JWT trở lại giao diện người dùng. Giao diện người dùng sẽ đính kèm JWT vào các yêu cầu mạng tới lớp API của máy khách. API sẽ thực hiện xác minh JWT như sau:
- Tìm nạp header của JWT, eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
- Có giải mã base64 header để lấy văn bản JSON đơn giản: {“typ”:”JWT”,”alg”:”HS256″}
- Xác minh giá trị của typ phải là JWT và giá trị của alg phải là HS256. Nếu không, nó sẽ từ chối JWT.
- Tìm nạp khóa bí mật và chạy cùng thao tác Base64URLSafe(HMACSHA256(…)) với header và payload của JWT.
- Kiểm tra chữ ký được tạo có giống với chữ ký từ JWT hay không, nếu không giống thì JWT sẽ bị từ chối.
Cấu trúc cơ bản của JSON Web Token
Một JSON Token Web được định dạng đúng sẽ bao gồm ba chuỗi được mã hóa Base64url-encoded và phân cách bằng dấu chấm (.), cấu trúc cụ thể như sau:
- Header: Chứa siêu dữ liệu về loại mã thông báo và sử dụng thuật toán mã hóa để tăng tính bảo mật của nội dung.
- Payload: Chứa các tuyên bố bảo mật có thể kiểm chứng được, chẳng hạn như danh tính của người dùng hay các quyền mà họ được phép.
- Signature: Được sử dụng để xác thực rằng mã thông báo (token) đáng tin cậy và không bị giả mạo. Khi sử dụng JWT, bạn nên kiểm tra chữ ký từ JWT trước khi tiến hành lưu trữ hay sử dụng chúng.
Header
Header trong JWT chủ yếu được sử dụng để mô tả các phương pháp mã hóa được áp dụng cho JSON Web Token như ký (signing) hay mã hóa (encryption). Các hoạt động mã hóa trong header giúp xác định xem JWT được ký hay được mã hóa hay sử dụng kỹ thuật thuật toán nào.
Header cũng có thể chứa dữ liệu về loại phương tiện hoặc nội dung của thông tin. Thông tin này sẽ hiển thị dưới dạng đối tượng JSON, sau đó JSON sẽ được mã hóa thành Base64url. Header đơn giản của JWT như sau:
{ "typ": "JWT", "alg": "HS256" }
Với ví dụ trên, bạn có thể thấy:
- typ: Cặp khóa đối tượng có chức năng công cấp mọi loại header của gói thông tin.
- alg: Cho biết thuật toán mã hóa được sử dụng.
Payload
Payload là một phần trong JWT và là nơi lưu trữ các dữ liệu của người dùng, dữ liệu này còn được gọi là JWT claims. Thông tin này được hiển thị dưới dạng đối tượng JSON, sau đó đối tượng JSON này sẽ được mã hóa thành Base64url. Bạn có thể đặt nhiều quyền xác nhận sở hữu và điều này là không bắt buộc trong một payload, khác với header.
Cấu trúc của một payload được hiển thị như sau:
{ "userId": "b07f85be-45da", "iss": "https://provider.domain.com/", "sub": "auth/some-hash-here", "exp": 153452683 }
Signature
Đây là phần thứ ba của JWT được sử dụng để xác minh tính xác thực của token. Header và payload được mã hóa Base64url và sau đó được dùng thuật toán để xác định header bằng khóa bí mật. Signature lúc này sau khi được thêm vào header và payload sẽ tạo thành token như sau:
header.payload.signature HASHINGALGO( base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret)
Đoạn mã đầy đủ về cấu trúc của một JWT như sau:
{ "header": { "alg": "HS256", "typ": "JWT" }, "payload": { "id": 123456789, "name": "Joseph" }, "secret": "ITviecBog"}
Kết quả hiển thị của JWT:
Khi nào nên sử dụng JSON Web Token? Một số điểm mạnh và điểm yếu
Một số ưu điểm cũng như điểm còn hạn chế của JSON Web Token như:
Điểm mạnh | Điểm yếu |
|
|
Vậy khi nào nên sử dụng JWT? Bạn cần sử dụng đến JSON Web Token khi:
- Ủy quyền: Đây là trường hợp phổ biến để sử dụng JWT. Sau khi người dùng đăng nhập, mỗi yêu cầu tiếp theo sẽ bao gồm JWT, cho phép người dùng truy cập các routes, dịch vụ và tài nguyên được phép bằng token. Đăng nhập một lần (Single Sign On) là một tính năng được JWT sử dụng rộng rãi bởi chi phí thấp cũng như dễ dàng sử dụng trên các miền (domain) khác nhau.
- Trao đổi thông tin: JWT là một phương pháp hữu ích để truyền thông tin một cách an toàn giữa các bên bởi chúng có thể được ký. Chẳng hạn như khi bạn sử dụng cặp khóa công khai/riêng tư, bạn có thể chắc chắn rằng về người gửi. Ngoài ra, vì chữ ký được tính bằng tiêu đề và tải trọng nên bạn cũng có thể xác minh rằng nội dung không bị giả mạo.
Bên cạnh đó, bạn cũng nên lưu ý không nên dùng JWT làm cookies cũng như quản lý phiên người dùng bởi chúng sẽ làm mất khả năng tự động quản lý của trình duyệt.
Đồng thời, không đặt quyền hoặc dữ liệu liên quan đến ứng dụng vì nó sẽ khiến đạt đến giới hạn kích thước của header.
JSON Web Token Claims
JSON Web Token Claims là những thông tin được xác nhận về một chủ đề (chẳng hạn như ID token có thể chứa xác nhận quyền sở hữu bằng tên của người dùng). Trong JWT, xác nhận quyền sở hữu xuất hiện dưới dạng cặp tên – giá trị trong đó tên luôn là một chuỗi và giá trị có thể là bất kỳ giá trị JSON nào.
JWT Claims có hai loại chính là:
- Registered (Đã đăng ký): Xác nhận quyền sở hữu tiêu chuẩn đã được đăng ký với The Internet Assigned Number Authority (IANA) và được xác định bởi JWT Specification để đảm bảo khả năng tương tác với các ứng dụng của bên thứ ba hoặc bên ngoài.
- Custom (Tùy chỉnh): Bao gồm các khiếu nại công khai (non-registered public) hoặc riêng tư chưa được đăng ký (private claims). Public claims có khả năng chống va chạm trong khi private claims có thể xảy ra xung đột.
Registered Claims
Registered Claims là JWT Specification xác định bảy yêu cầu dành riêng không bắt buộc nhưng được khuyến nghị để cho phép khả năng tương tác với các ứng dụng của bên thứ ba. Cụ thể như:
- Iss (issuer): Nhà phát hành JWT.
- Sub (subject): Chủ đề của JWT (người dùng).
- Aud (audience): Người nhận mà JWT hướng tới.
- Exp (expiration time): Thời gian sau đó JWT hết hạn.
- Nbf (not before time): Thời gian trước đó JWT không được chấp nhận để xử lý.
- Iat (issued at time): Thời điểm JWT được cấp, có thể được sử dụng để xác định tuổi của JWT.
- Jti (JWT ID): Mã định danh duy nhất, có thể được sử dụng để ngăn JWT được phát lại (chỉ cho phép sử dụng token duy nhất).
Custom Claims
Bạn có thể xác định xác nhận custom claims của mình mà bạn kiểm soát và có thể chúng vào token bằng cách sử dụng Action. Chẳng hạn như:
- Thêm địa chỉ email của người dùng vào token truy cập (An access token) và sử dụng địa chỉ đó để nhận dạng người dùng duy nhất.
- Thêm thông tin tùy chỉnh được lưu trữ trong hồ sơ người dùng vào ID token.
Miễn là Action được thực hiện, Custom Claims được thêm vào sẽ xuất hiện trong mã thông báo mới được phát hành khi sử dụng token làm mới (a refresh token).
Ví dụ, hồ sơ người dùng chuẩn hóa được lưu trữ như sau:
{ "email": "jane@example.com", "email_verified": true, "user_id": "custom|123", "favorite_color": "blue", "user_metadata": { "preferred_contact": "email" } }
Với cấu hình trên, trình duyệt sẽ trả lại các ID token claims cho ứng dụng của bạn như sau:
{ "email": "jane@example.com", "email_verified": true, "iss": "https://my-domain.auth0.com/", "sub": "custom|123", "aud": "my_client_id", "iat": 1311280970, "exp": 1311281970 }
Qua ví dụ trên, có thể thấy được:
- Xác nhận quyền sở hữu phụ chứa giá trị của thuộc tính user-id.
- Cả thuộc tính favorite_color và user_metadata đều không xuất hiện vì OpenID Connect (OIDC) không xác định các standard claims (quyền sở hữu tiêu chuẩn) đại diện cho favorite_color hoặc user_metadata.
Public Claims
Bạn có thể tạo Custom Claims để công chúng sử dụng, chứa các thông tin chung như tên và email.
Nếu bạn tạo Public Claims, bạn phải đăng ký hoặc sử dụng các tên chống xung đột thông qua không gian tên và thực hiện các biện pháp ngăn chặn hợp lý để đảm bảo rằng bạn có quyền kiểm soát tên mà mình được sử dụng.
Private Claims
Bạn có thể tạo Private Claims để chia sẻ thông tin cụ thể cho ứng dụng của mình. Ví dụ như trong khi Public Claims có thể chứa thông tin chung như họ tên và email, thì Private Claims sẽ cụ thể hơn, chẳng hạn như ID nhân viên, tên bộ phận,…
Câu hỏi thường gặp về JSON Web Token
JSON Web Token có thể hoạt động cùng với HTTP không?
JWT là một lựa chọn tốt để hoạt động trong môi trường HTML và HTTP. JSON nhỏ gọn và ít dài dòng hơn XML, thường được truyền tải trong tiêu đề Authorization trong HTTP. Máy chủ có thể xác minh chữ ký của JWT và trích xuất thông tin xác thực từ JWT payload.
Rủi ro khi sử dụng JSON Web Token là gì?
Một số rủi ro có thể gặp khi sử dụng JSON Web Token như:
- Lỗ hỏng chữ ký: Nếu khóa bí mật được sử dụng để ký JWT bị lộ, kẻ tấn công có thể lợi dụng để tạo JWT giả.
- Lỗ hỏng xác thực: Nếu cấu hình JWT không được chính xác, kẻ tấn công có thể truy cập và giả mạo danh tính người dùng.
Tham khảo Việc làm Front-end hấp dẫn trên ITviec
Tổng kết về JSON Web Token
Hy vọng qua bài viết, bạn sẽ có góc nhìn tổng quan hơn về định dạng cấu trúc JSON Web Token cũng như cách hoạt động của chúng. Nếu bạn đang có định hướng trở thành Web Developer hoặc phát triển một ứng dụng web, JSON Web Token sẽ là một trong những phương pháp hữu ích giúp bạn tối ưu cũng như đơn giản hóa quá trình xử lý dữ liệu.
Xem thêm: Javascript Developer là gì? Các hướng phát triển của Javascript Developer