JWT là gì?

Dạo gần đây cái blog móc meo này không cập nhật gì vì bận với dự án cày toàn công nghệ của Yahoo như Athenz, CorpIT,… mà từ mấy này mình học được nhiều thứ trong đó có phương pháp Authentication dùng JWT (JSON Web Token). Cái này thấy đã ra đời lâu rồi người ta áp dụng nhiều rồi mà giờ mình mới nghiên cứu tới! viết bài này để tự share cho mình, JWT là gì và những lợi ích gì mà JWT có thể đem lại cho Web Service ngoài việc chứng thực.

JWT là gì?

JWT (JSON Web Token) là 1 tiêu chuẩn mở (RFC 7519) định nghĩa cách thức truyền tin an toàn giữa các bên bởi JSON. Thông tin này có thể được xác thực và đánh dấu tin cậy nhờ vào “chữ ký” của nó. Phần chữ ký của JWT sẽ được mã hóa lại bằng HMAC hoặc RSA.

mô hình 1 json web token

Những đặc điểm nổi bật của JWT:

  1. Kích thước nhỏ: JWT có thể được truyền thông qua query parameter trên URL, HTTP Header, Cookie, Post…. Kích thước nhỏ hơn ứng với công việc truyền tải sẽ nhanh hơn. Dưới đây là cách thức truyền token vào trong HTTP Header sử dụng Bearer Schema.
  2. Khép kín: toàn bộ những thông tin bảo mật sẽ được đóng kính trong phần Payload của JWT và được mã hóa bởi secret key.

Tại sao dùng JWT?

Dưới đây là 1 vài kịch bản nên dùng JWT:

  • Authentication: Đây là kịch bản phổ biến nhất cho việc sử dụng JWT. Một khi người dùng đã đăng nhập vào hệ thống thì những request tiếp theo từ phía người dùng sẽ chứa thêm mã JWT, cho phép người dùng quyền truy cập vào các đường dẫn, dịch vụ, và tài nguyên mà cần phải có sự cho phép nếu có mã Token đó. Phương pháp này không bị ảnh hưởng bởi Cross-Origin Resource Sharing (CORS) do nó không sử dụng cookie.

    Client application                                            API
        --------                                              --------
            |                                                      |
            |                   GET /api/employees                 |
            |----------------------------------------------------->|
            |                     403 Forbidden                    |
            |<-----------------------------------------------------|
            |                                                      |
            |                                                      |
            |                 POST /api/authenticate               |
            |     { login: "userid", password: "passsecurity" }    |
            |----------------------------------------------------->|
            |                      200 Success                     |
            |             { token: "my.personal.token" }           |
            |<-----------------------------------------------------|
            |                                                      |
            |                                                      |
            |                 GET /api/employees                   |
            | Header { "Authorization: Bearer "my.personal.token" }|
            |----------------------------------------------------->|
            |                      200 Success                     |
            |<-----------------------------------------------------|
            |                                                      |
    
  • Trao đổi thông tin: JWT dùng để truyền tin an toàn và bảo mật giữa các service với nhau bởi Signature. Signature được tạo ra bằng việc kết hợp cả phần Header, Payload và secret key nên thông qua đó ta có thể xác nhận được chữ ký có bị giả mạo hay không.

Cấu trúc của JWT:

JWT bao gồm 3 phần, được ngăn cách nhau bởi dấu chấm (.):

  1. Header
  2. Payload
  3. Signature

Tổng quát thì nó có dạng như sau:

Header:

Phần Header dùng để khai báo kiểu chữ ký và thuật toán mã hóa sẽ dùng cho cái token của chúng ta.

Đoạn Header này khai báo rằng đối tượng được mã hóa là 1 JWT (để phân biệt với JWS hay JWE), và chữ ký của nó sử dụng thuật toán mã hóa HMAC SHA-256.

Đoạn Header này sẽ được mã hóa base64url, và ta thu được phần đầu tiên của JWT:

Chú ý rằng mình viết ở phía trên là base64url chứ không phải là base64. Về cơ bản 2 cái này là tương tự nhau nhưng giữa chúng vẫn có những sự khác biệt:

  • Không thêm = vào
  • Các ký tự + và / sẽ được thay thế bằng – và _

​Các bạn có thể so sánh sự khác biệt của chúng ở trang web encode online này:
http://kjur.github.io/jsjws/tool_b64uenc.html

Chúng ta có thể tự triển khai 1 hàm encode base64url do chính mình tạo ra. Dưới đây là code mô phỏng bằng Javascript:

Ở đoạn code trên mình đã sử dụng thư viện CryptoJS để có thể mã hóa base64 rồi sau đó loại bỏ các ký tự = và thay thế các ký tự + / đi.

Để có thể sử dụng được hàm trên, đầu vào của bạn cần là 1 mảng byte ở định dạng UTF-8. Ta có thể chuyển đổi từ xâu ký tự sang mảng byte bằng 1 hàm khác cũng được cung cấp bởi CryptoJS:

Cuối cùng ta đã thu được phần đầu tiên của JWT:

Payload (Claims):

Phần thứ 2 của token đó là Payload, nơi chứa các nội dung của thông tin (claim). Thông tin truyền đi có thể là mô tả của 1 thực thể (ví dụ như người dùng) hoặc cũng có thể là các thông tin bổ sung thêm cho phần Header. Nhìn chung, chúng được chia làm 3 loại: reserved, public và private.

  1. Reserved: là những thông tin đã được quy định ở trong IANA JSON Web Token Claims registry. Chúng bao gồm: Chú ý rằng các khóa của claim đều chỉ dài 3 ký tự vì mục đích giảm kích thước của Token
    • iss (issuer): tổ chức phát hành token
    • sub (subject): chủ đề của token
    • aud (audience): đối tượng sử dụng token
    • exp (expired time): thời điểm token sẽ hết hạn
    • nbf (not before time): token sẽ chưa hợp lệ trước thời điểm này
    • iat (issued at): thời điểm token được phát hành, tính theo UNIX time
    • jti: JWT ID
  2. Public: Khóa nên được quy định ở trong IANA JSON Web Token Registry hoặc là 1 URI có chứa không gian tên không bị trùng lặp.
  3. Private: Phần thông tin bảo mật dùng để gửi qua các services.

 

Ví dụ Payload:

Mã hóa base64url ta thu được phần thứ 2 của token:

Signature:

Phần chữ ký được tạo bằng cách kết hợp 2 phần Header + Payload, rồi mã hóa nó lại bằng 1 giải thuật encode nào đó, càng phức tạp thì càng tốt, ví dụ như HMAC SHA-256

Rồi ta sẽ thu được phần cuối của token:

Putting All Together:

Gom lại từ ví dụ trên sẽ có dạng là:

Và đây là đoạn code Javascript triển khai toàn bộ công việc trên:

Source code để hiểu tạo JWT thôi vì hiện nay đã có rất nhiều library hỗ trợ việc trên rất tốt. Bạn có thể tham khảo: https://jwt.io/

Nếu đang lập trình Node.js thì nên dùng: https://github.com/auth0/node-jsonwebtoken

Sẽ viết bài hướng dẫn dùng Nodejs để build JWT sau…

Sliding Sidebar

About Me

About Me

Hello, my name is Dũng (Johnny). Welcome to my blog.

As I’m a developer, I write about topics related to the field of programming, mainly from a technical point of view. On this blog you’ll find posts which encourage discussion, information about development trends, case studies, reviews, tutorials, tips on how to improve your effectiveness, and anything else that might be fascinating to people from the IT industry.
I love PHP, NodeJS, Java,... and Fullstack.