I. Kiến thức chuẩn bị
1. Kiểu dữ liệu JSON
JSON (JavaScript Object Notation) là một định dạng dữ liệu nhẹ và độc lập với ngôn ngữ lập trình, được thiết kế để truyền tải và lưu trữ dữ liệu. JSON có định dạng giống như JavaScript Object, với các cặp key - value trong dấu ngoặc nhọn { }
và được phân cách bằng dấu phẩy.
{ "name": "John", "age": 30, "address": { "street": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345" }, "phoneNumbers": [ { "type": "home", "number": "555-555-1234" }, { "type": "work", "number": "555-555-5678" } ]
}
2. JSON web tokens là gì?
Các phương pháp xác thực truyền thống như cookie và session được sử dụng rộng rãi trong ứng dụng web. Tuy nhiên, theo thời gian, với sự phát triển của các ứng dụng di động và các ứng dụng web ngày càng trở nên phức tạp hơn, dẫn đến một số vấn đề như sau:
- Mỗi khi người dùng xác thực thành công trong ứng dụng, hệ thống cần lưu trữ một bản ghi chứa thông tin xác thực này (phiên) trong bộ nhớ. Với sự gia tăng số lượng người dùng xác thực trong thời điểm ngắn, chi phí sử dụng cho việc lưu trữ và xử lý sẽ tăng lên đáng kể.
- Sau khi người dùng xác thực, nếu bản ghi được lưu trữ trong máy chủ đó sẽ đồng nghĩa với việc người dùng chỉ có quyền truy cập vào các tài nguyên cấp phép trên cùng máy chủ. Đồng nghĩa với việc ứng dụng sẽ bị giới hạn về khả năng mở rộng.
- Thông tin lưu trữ trong session thường không nhiều. Giới hạn về khả năng lưu trữ thông tin xác thực.
- Nếu session bị đánh cắp, ứng dụng và người dùng có nguy cơ bị tấn công CSRF, XSRF.
Từ đó, JSON web tokens (JWT) được thiết kế nhằm cung cấp một cách thức đơn giản và bảo mật để xác thực và trao đổi thông tin giữa các ứng dụng web và di động. JWT là một chuẩn mã hóa thông tin dựa trên định dạng JSON, được đưa vào các tiêu chuẩn Internet trong RFC 7519 vào năm .
3. Cấu tạo JWT
Như hình vẽ, chúng ta thấy một chuỗi JWT được cấu tạo bởi ba bộ phận header, payload, signature theo thứ tự đó, phân cách nhau bởi dấu chấm .
eyJraWQiOiIyNTg4NzYyMy1iNjljLTQ0ODEtYjQ3Ni1lNTk3MTdlZjg4ZGQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY4Mzk1MzczNn0.yTR_bNCN4prjtvhkPy43n1CI93EOyxCP-xWtAgOrGSoIo0q2-nYhisGh5k0o-IfqlJGt6QrYSXykjvej_0_1WndSHUcv5rsC3b--37wyyNnyzVP3o37fFZOVxaLk6zpdpxeSJPmz0L1j1rCDeJqU73tIjpmwTulrxNq5zx-sO-AnopHaFzIfletzBAFQtrKETwaWc6rUtzVIL5BnkSTsrnQMFevg57CxfD8Qqvsu-ePfEPJ4xcmhSJcQLuriVUNmkFLmpGO2WRnrCgyga4uCIde0cdNsYN7UBrKs9E8akGxUU_HbRwmrBKaTzPDKrxQeV7nsb6TZOOexS0cFx7cJwg
Chúng ta sẽ lần lượt tìm hiểu từng bộ phận.
3.1. Header
Bộ phận header trong JWT chứa thông tin về loại token và thuật toán mã hóa được sử dụng để tạo ra chữ ký số cho token. Nó được tạo thành bằng cách sử dụng Base64 encode đối tượng JSON. Thường bao gồm hai thuộc tính alg (algorithm) và typ (type). Bạn có thể decode Base64 để thấy rõ hơn, ví dụ header sau cho biết JWT sử dụng thuật toán mã hóa RSA-SHA256 (RS256) và type JWT đối với token JWT.
{ "kid":"25887623-b69c-4481-b476-e59717ef88dd", "alg":"RS256", "typ": "JWT"
}
Khi xác thực JWT, phía bên nhận cần phải kiểm tra header để đảm bảo rằng token được mã hóa và giải mã bằng cùng một thuật toán.
3.2. Payload
Bộ phận payload chứa thông tin liên quan đến người dùng hoặc ứng dụng mà token đại diện. Giống với header, payload cũng được hiển thị dưới dạng mã hóa Base64. Nó chứa các thông tin khác nhau tùy thuộc vào mục đích sử dụng của JWT, nhưng thường bao gồm các thông tin như:
iss
(issuer): người phát hành token.sub
(subject): chủ sở hữu của token, thường là ID người dùng.aud
(audience): ứng dụng hoặc API sử dụng token.exp
(expiration time): thời gian hết hạn của token.nbf
(not before time): thời gian mà token không được sử dụng trước khi hợp lệ.iat
(issued at time): thời gian phát hành token.jti
(JWT ID): ID duy nhất cho mỗi token.
Các thuộc tính khác cũng có thể được thêm linh hoạt vào payload tùy thuộc vào mục đích sử dụng của JWT. Ví dụ, nếu JWT được sử dụng để xác thực người dùng, payload có thể chứa thông tin về tên người dùng, quyền hạn, thông tin liên lạc và các chi tiết khác về người dùng.
Ví dụ về payload trong JWT:
{ "iss":"viblosecurity", "sub":"11d3-ae19-be29-8020", "admin": false, "email": "_@.com", "exp":1683953736
}
Payload trong JWT cung cấp cho phía bên nhận thông tin về người dùng hoặc ứng dụng được xác thực bởi token. Khi xác thực JWT, bên nhận có thể trích xuất thông tin từ payload để thực hiện các xử lý tùy thuộc vào mục đích sử dụng của JWT.
3.3. Signature
Hai bộ phận trước header và payload đều được mã hóa bằng Base64, giúp server front end có thể giải mã truy xuất nội dung dễ dàng. Phần signature trong JWT là một chuỗi được tạo ra bằng cách kết hợp Header và Payload với một Secret Key sử dụng một thuật toán hash.
Cụ thể, quá trình tạo signature trong JWT sử dụng thuật toán mã hóa hash như HMAC (Hash-based Message Authentication Code) hoặc RSA (Rivest-Shamir-Adleman) để tạo ra một chuỗi ký tự đại diện cho signature, được gắn vào cuối của JWT. Thuật toán HMAC sử dụng một khóa bí mật chung được biết đến bởi cả người tạo JWT và người xác thực JWT để tạo ra signature, trong khi thuật toán RSA sử dụng cặp khóa công khai và khóa riêng tư để thực hiện quá trình tạo signature.
Việc sử dụng signature giúp đảm bảo tính toàn vẹn (Integrity) của JWT và đảm bảo rằng không ai có thể sửa đổi dữ liệu trong Payload mà không bị phát hiện. Điều này đặc biệt quan trọng khi sử dụng JWT để truyền tải thông tin xác thực giữa các thành phần của hệ thống. Khi JWT được gửi đi, người nhận có thể kiểm tra signature để xác nhận tính hợp lệ của JWT.
Cuối cùng, các bạn có thể tổng hợp và ôn lại kiến thức từng bộ phận trong một token JWT qua hình ảnh sau:
4. Khi nào nên sử dụng JWT?
JWT được sử dụng trong nhiều tình huống khác nhau trong các ứng dụng web và di động. Dưới đây là một số tình huống phổ biến:
4.1. Xác thực người dùng
Phổ biến nhất là sử dụng JWT để xác thực người dùng và truy cập các tài nguyên trang web cũng như API.
Ví dụ, khi người dùng đăng nhập vào một ứng dụng web, ứng dụng sẽ cấp cho người dùng một JWT trong Cookie, sau đó mỗi lần người dùng gửi yêu cầu đến ứng dụng, JWT đó sẽ được gửi cùng với yêu cầu để xác thực danh tính.
4.2. Quản lý tài khoản người dùng
JWT có thể được sử dụng để quản lý tài khoản người dùng. Thông tin tài khoản sẽ được lưu trữ trong payload của JWT và được sử dụng để xác thực và cấp quyền truy cập cho người dùng khi truy cập vào các tài nguyên khi JWT được kiểm tra là hợp lệ.
4.3. Trao đổi thông tin giữa các ứng dụng
JWT có thể được sử dụng để chuyển thông tin giữa các ứng dụng khác nhau. Thay vì phải xác thực riêng từng lần khi gửi yêu cầu đến dịch vụ khác, JWT được sử dụng để truyền tải thông tin xác thực giữa các dịch vụ một cách an toàn và tiện lợi.