Header Ads

Seo Services

Bài viết trước mình đã cùng anh em tìm hiểu về cookie-based authentication và token-based authentication. Đây là hai khái niệm cơ bản mà anh em nên nắm được trước khi tiếp tục bài viết hôm nay liên quan đến JSON Web Tokens (JWT)

Nếu anh em nào chưa nắm được có thể tham khảo tại đây  

🔔Lưu ý!

Bài này đúng là sẽ hơi nặng lý thuyết một chút nhưng anh em chịu khó đọc nha vì đây thực sự là những lý thuyết quan trọng để anh em có thể hiểu hơn về JWT và cả những nội dung mình đã đề cập trong các bài viết trước.

Ngoài ra cuối bài viết mình có một đoạn code viết bằng Java và sử dụng thư viện io.jsonwebtoken để triển khai ví dụ về việc làm sao sinh ra một JWT cũng như làm sao decode JWT đó. Anh em có thể tham khảo nhé!

Bây giờ thì cùng mình bắt đầu bài viết hôm nay thôi!

1. JWT là gì?

Chúng ta thấy rằng trong những năm trở lại đây mô hình xây dựng một hệ thống có nhiều thay đổi do sự cải tiến không ngừng của các thiết bị thông minh. Các trang web đơn thuẩn không còn phổ biến như trước mà thay vào đó và các web app, mobile app... tương tác với nhau thông qua APIs.

Từ đây kéo theo một hệ quả đó là các hệ thống trao đổi dữ liệu với nhau nhiều hơn về cả khối lượng và số lượng thông tin truyền tải.

Bài toán đặt ra là làm sao để quá trình trao đổi thông tin, dữ liệu giữa các hệ thống này trở nên an toàn, đơn giản và hiệu quả hơn?

Và sự ra đời của JWT nói riêng hay web token nói chung đã góp phần không nhỏ để giải quyết bài toán này. Vậy JWT - JSON Web Token là gì?

Có rất nhiều định nghĩa khác nhau nhưng ở đây mình trích từ trang chủ như sau:

"JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA"

Anh em lưu ý 3 đặc điểm chính:

Compact and self-contained: Một đặc điểm và cũng là lợi điểm của JWT nếu đem so sánh với SWT (Simple Web Tokens) hay SAML (Security Assertion Markup Language Tokens) chính là sự gọn nhẹ và độc lập trong việc đóng gói và truyền tải thông tin.

JSON object: JSON (JavaScript Object Notation) là một kiểu cấu trúc dữ liệu được xây dựng theo các cặp key - value. Bản chất của JWT cũng là một chuỗi của các JSON object được mã hóa.

Signed using a secret or public/private key pair: Đã là token thì tất nhiên phải được bảo mật và đối với JWT thì chúng ta có hai phương pháp ký để đảm bảo tính toàn vẹn cũng như bảo mật của dữ liệu đó là sử dụng secret key (ký bằng thuật toán HMAC) hoặc sử dụng public/private key (ký bằng thuật toán RSA hoặc ECDSA)

2. Sử dụng khi nào? 

Có khá nhiều trường hợp (usecase) mà việc sử dụng JWT là phù hợp và đem lại hiệu quả nhưng sau đây mình chỉ đề cập tới 2 trường hợp điểm hình nhất:

Authorization: Đây là trường hợp chúng ta hay nhắc đến nhất khi sử dụng JWT.  Như mình đã trình bày trong bài viết trước sau khi người dùng login vào hệ thống sẽ được nhận lại một JWT. 

Mỗi request sau đó được đính kèm JWT này vào phần header để thực hiện việc như phân quyền xem người dùng được quyền truy cập vào APIs nào, service nào, tài nguyên nào. Một ví dụ mà anh em thường gặp nhất của việc ứng dụng JWT đó là Single Sign On.

Infomation Exchange: Việc truyền tải những thông tin "nhạy cảm" giữa các hệ thống phải đảm bảo được yếu tố bảo mật. JWT làm rất tốt việc này vì như mình đã trình bày trong phần 1 thì JWT được sinh ra từ việc ký với secret key hoặc public/private key để đảm bảo tính toàn vẹn cũng như an toàn thông tin.

3. Cấu trúc ra sao?

Một chuỗi JWT sẽ bao gồm 3 phần phân cách nhau bởi dấu chấm (.)

[Header].[Payload].[Signature]

1. Header

Thông thường header sẽ bao gồm 2 phần: 

- Loại token

-Thuật toán dùng để ký

Trong đó loại token ở trường hợp này là JWT còn thuật toán ví dụ như HMAC SHA256 hoặc RSA

Ví dụ:

{
  "alg": "HS256",
  "typ": "JWT"
}

Sau đó, header sẽ được mã hóa base64Url và là phần đầu tiên của JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

2. Payload

Phần thứ hai của JWT là payload chứa thông tin (claims) về đối tượng truy cập hệ thống (user) và các thông tin được bổ sung thêm. Có 3 loại thông tin có thể được đính trong phần payload:

Registered claims: Là những trường thông tin được định nghĩa sẵn tuy không bắt buộc nhưng được khuyến khích sử dụng ví dụ như: iss (issuer), exp (expiration time), sub (subject), aud (audience)...

🔔Lưu ý!

Ở đây anh em thấy tên các trường này chỉ có 3 chữ cái thì mục đích là sau khi mã hóa chuỗi JWT sẽ nhẹ nhất có thể.

Public claims: Là những trường thông tin chúng ta tự định nghĩa, tuy nhiên có một lưu ý là tên các trường này không được trùng với các trường được định nghĩa sẵn trong mục registerd claims. Anh em có thể tham khảo danh sách các trường đó ở đây

Private claims: Là những trường thông tin được quy ước giữa các hệ thống với nhau và khác với registered claims cũng như public claims.

Ví dụ payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 2023120134,
  "email": "laptrinhb2a@gmail.com"
}

Sau đó, payload cũng sẽ được mã hóa base64Url và là phần thứ hai của JWT:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjIwMjMxMjAxMzQsImVtYWlsIjoibGFwdHJpbmhiMmFAZ21haWwuY29tIn0

3. Signature

Để tạo ra được signature chúng ta sẽ phải có: base64Url encoded header, base64Url encoded payload, secret key, sign algorithm 

Ví dụ nếu mình có secret key:

oeRaYY7Wo24sDqKSX3IM9ASGmdGPmkTd9jo1QTy4b7P9Ze5_9hKolVX8xNrQDcNRfVEdTZNOuOyqEGhXEbdJI-ZQ19k_o9MI0y3eZN2lp9jow55FfXMiINEdt1XR85VipRLSOkT6kSpzs2x-jbLDiz9iFVzkd81YKxMgPA7VfZeQUm4n-mOmnWMaVX30zGFU4L3oPBctYKkl4dYfqYWqRNfrgPJVi5DGFjywgxx0ASEiJHtV72paI3fDR2XwlSkyhhmY-ICjCRmsJN4fX1pdoL8a18-aQrvyu4j0Os6dVPYIoPvvY0SAZtWYKHfM15g7A3HD4cVREf9cUsprCRK93w

Thì sử dụng thuật toán HMAC SHA256 với secret key đó sẽ có signature được ký như sau:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  oeRaYY7Wo24sDqKSX3IM9ASGmdGPmk...)

Kết quả chúng ta có signature: VgaKn128L22HIyc32Ho-qHtnM50LvKr-2cNsaXjRNPY

Signature đảm bảo được hai yếu tố:

- Tính toàn vẹn của dữ liệu: Sau khi ký, trong quá trình truyền tải thông tin nếu ai đó muốn chỉnh sửa thông tin nhưng không có secret key thì việc chỉnh sửa là không thể hay chính xác hơn là rất rất khó.

- Xác minh được người gửi thông tin: Trong trường hợp sử dụng private key chúng ta cũng có thể xác thực được có đúng người gửi hay không.

Và cuối cùng JWT sẽ được sinh ra bằng cách kết hợp 3 phần header, payload, signature lại như sau:

4. Hoạt động như thế nào?

Đến đây chắc anh em cũng hình dung được cấu trúc của JWT rồi, vậy quay lại với câu hỏi JWT hoạt động như thế nào?

Để phần nào trả lời được câu hỏi này thì mình lại phải "hai ly ri còm men" anh em đọc bài trước một chút. Bài viết về token based và cookie based authentication của mình tại đây

Đối với các hệ thống sử dụng token-based authentication hay cụ thể hơn là sử dụng JWT thì khi người dùng đăng nhập vào hệ thống sẽ nhận lại một JWT nếu đăng nhập thành công.

Từ các request tiếp theo JWT sẽ được đính kèm trong phần header và thường có dạng như sau:

Authorization: Bearer <JWT>

Ví dụ:

curl --location 'https://api.laptrinhb2a/posts' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjIwMjMxMjAxMzQsImVtYWlsIjoibGFwdHJpbmhiMmFAZ21haWwuY29tIn0.Qa24mhnjonbkOm18YK8kKot-l8ULB0AfMFBN5L-KoXA' \
--header 'Content-Type: application/json' \
--data '{
    ...
}'

Hệ thống sẽ sử dụng JWT này để xác thực và phân quyền người dùng được phép truy cập vào những tài nguyên, services, APIs nào của hệ thống.

5. Tham khảo

Tài liệu tham khảo:

https://jwt.io/introduction

https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-structure

https://auth0.com/resources/ebooks/jwt-handbook/thankyou

Source code:

https://github.com/canhnd99/jwt-java

Hẹn gặp lại anh em trong các bài viết tiếp theo nhé! Thanks all ❤️❤️❤️

Không có nhận xét nào:

Được tạo bởi Blogger.