Token-based authentication là gì?
Token-based authentication là phương thức xác thực bằng chuỗi má hóa. Một hệ thống sử dụng Token-based authentication cho phép người dùng nhập user/password để nhận về 1 chuỗi token. Chuỗi Token này được sử dụng để “xác minh” quyền truy cập vào tài nguyên mà không cần phải cung cấp lại username/password nữa.
Tiếp theo, chúng ta sẽ tìm hiểu về phương pháp sử dụng Token-based authentication bằng JWT (Json Web Token).
JWT – JSON Web Token là gì?
JSON Web Token là một chuỗi mã hóa mà nguồn gốc ban đầu là một chuỗi JSON. Chuỗi thông tin dạng JSON bằng phương pháp mã hóa nào đó, nó trở thành 1 chuỗi ký tự lộn xộn nhìn vào sẽ rất khó hiểu.
>>> Xem thêm JSON là gì?
Định nghĩa theo tiêu chuẩn:
JSON Web Token (JWT) 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 thành viên bằng 1 đối tượng 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. (Nguồn: techmaster.vn)
Như vậy, Bảo mật JWT là phuơng pháp xác thực quyền truy cập (Authentication) bằng JSON Web Token.
Cấu trúc của một JWT
Dưới đây là 1 JSON Web Token
JWT trên bao gồm 3 phần:
- Header
- Payload
- Signature
Cấu trúc của nó theo format như sau
<base64-encoded header>.<base64-encoded payload>.<HMACSHA256(base64-encoded signature)>
Header
Header bao gồm hai phần chính:
- typ – Loại token (mặc định là JWT – cho biết đây là một Token JWT)
- alg – Thuật toán đã dùng để mã hóa (HMAC SHA256 – HS256 hoặc RSA).
{ "alg": "HS256", "typ": "JWT" }
Chuỗi JSON trên sau khi được mã hóa base64url sẽ trở thành như sau
String header = "{"alg":"HS256","typ":"JWT"}"; System.out.println(Base64.getUrlEncoder().encodeToString(header.getBytes()));
Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload
Là 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. Chúng được chia làm 3 loại: reserved, public và private
- Reserved: là những thông tin đã được quy định ở trong IANA JSON Web Token Claims registry. Những thông tin này không có cái nào là bắt buộc cả. Tuy nhiên tùy vào từng ưng dụng bạn implement mà hãy ràng buộc yêu cầu bắt buộc đối với những thông tin cần thiết
- iss (issuer): tổ chức phát hành token (không bắt buộc)
- sub (subject): chủ đề của token (không bắt buộc)
- aud (audience): đối tượng sử dụng token (không bắt buộc)
- exp (expired time): thời điểm token sẽ hết hạn (không bắt buộc)
- 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
- Public: Khóa có thể define tùy theo ý muốn của người sử dụng JWT. Tuy nhiên để tránh trùng lặp, khó 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. Ví dụ:
"https://www.topdev.vn/jwt_claims/is_admin": true
- Private: Phần thông tin thêm dùng để truyền qua giữa các client. Ví dụ
{ "sub": "1234567890", "name": "Hai Nguyen", "admin": true }
Ta có ví dụ cho phần Payload như sau
{ "sub": "nhs3108", "exp": 1558065420 }
Đoạn JSON trên sau khi được mã hóa base64url sẽ trở thành như sau
String payload = "{"sub":"nhs3108","exp":1558063837}"; System.out.println(Base64.getUrlEncoder().encodeToString(payload.getBytes()));
Output: eyJzdWIiOiJuaHMzMTA4IiwiZXhwIjoxNTU4MDYzODM3fQ
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 bất kỳ ví dụ như HMAC SHA-256
Có thể xem lại công thức sau:
<base64-encoded header>.<base64-encoded payload>.<HMACSHA256(base64-encoded signature)>
Với signature là phần kết hợp giữa header và payload Ở 2 phần trên, ta đã có
String header = "{"alg":"HS256","typ":"JWT"}"; String encodedHeader = Base64.getUrlEncoder().encodeToString(header.getBytes()); String payload = "{"sub":"nhs3108","exp":1558063837}"; String encodedPayload = Base64.getUrlEncoder().encodeToString(payload.getBytes()); String signature = encodedHeader + "." + encodedPayload; String encodedSignature = HMACSHA256.encode(signature, scretKey); System.out.println(encodedSignature);
Output 449KVmOFWcpsa3OUjnYGm-f1QWhY8N-DerKDfTK0JQm1Nc
Tổng lại 3 phần, có chuỗi JWT như sau
eyJhbGciOiJIUzI1NiIsxz4InR5cCI6IkpXVCJ9.eyJzdWIi54OiJuaHMzMTA4IiwiZXhwIjoxNTU4MDYzODM3fQ.449KVmOFWcpOUjnYGm-f1QWh54Y8N-DerKDfTK0JQm1Nc
>>> Xem thêm: JSON-LD là gì ? Tổng quan về JSON-LD cho người mới
Flow hệ thống sử dụng JWT
Chúng ta sẽ dùng sở đồ sau để hình dung
Nhìn vào hình ta có thể thấy flow đi như sau:
- User thực hiện login bằng cách gửi id/password hay sử dụng các tài khoản mạng xã hội lên phía Authentication Server (Server xác thực)
- Authentication Server tiếp nhận các dữ liệu mà User gửi lên để phục vụ cho việc xác thực người dùng. Trong trường hợp thành công, Authentication Server sẽ tạo một JWT và trả về cho người dùng thông qua response.
- Người dùng nhận được JWT do Authentication Server vừa mới trả về làm “chìa khóa” để thực hiện các “lệnh” tiếp theo đối với Application Server.
- Application Server trước khi thực hiện yêu cầu được gọi từ phía User, sẽ verify JWT gửi lên. Nếu OK, tiếp tục thực hiện yêu cầu được gọi.
Hệ thống Verify chuỗi JWT thế nào?
Câu hỏi đặt ra ở đây là hệ thống Verify JWT thế nào:
- Chuỗi JWT có cấu trúc H.P.S được Client gửi lên. Server sẽ làm tương tự như sau
- Set S1 = S
- Set S2 = HMAC(SHA256(H.P) vỡi secret key của hệ thống) (Giả sử hệ thống sử dụng encryption algorithms SHA256)
- So sánh S1 == S2 ?
- Nếu S1 và S2 khớp nhau, tức là chữ ký hợp lệ, hệ thống mới tiếp decode payload và tục kiểm tra các data trong payload. Ví dụ trường exp (expiration date).
Khi nào sử dụng JWT?
Với JWT, bạn không cần phải giữ session data trên server để xác thực user. Luồng đi như sau:
-
- Người dùng gọi authentication service để gửi username/password
- Authentication service phản hồi cho người dùng mã JWT, cái này sẽ định nghĩa xem user là ai
- Người dùng yêu cầu truy cập một dịch vụ được bảo mật bằng việc gửi token lên
- Lớp bảo mật sẽ check chữ ký trên token và nếu đó là quyền truy cập hợp lệ thì được tiếp tục truy cập
Các sessions sẽ có thời hạn hết hạn và cần phải được xử lý kiểu xoá đi các session hết hạn này. JWT hoàn toàn có thể sở hữu chính expiry date của chính nó kèm với dữ liệu user. Cho nên khi tầng Security check authen của JWT, nó có thể check expiry time của token và đơn giản là từ chối truy cập.
Nếu không sử dụng session thì bạn mới có thể ứng dụng tạo một service thuần RESTful, bởi vì một service thuần RESTful được định nghĩa là phải stateless. Với dung lượng nhỏ, JWT có thể được gửi lên với mọi request cũng giống như session cookie. Nhưng ko giống với session cookie, nó ko cần phải trỏ đến bất kì dữ liệu nào được lưu trữ trên server, bản thân JWT đã có dữ liệu.
RESTful API Services
>>> Xem thêm Restful API là gì?
Bài viết có sự tham khảo tới các bài viết sau: https://jwt.io/introduction/
Xem thêm việc làm JSON hot nhất trên TopDev