Tìm hiểu Json Web Token (JWT)
Bài đăng này đã không được cập nhật trong 5 năm
Trong bài viết này chúng ta sẽ tìm Jwt là gì ? Cũng như cấu tạo và cách thức hoạt động của nó ra sao ?
Json Web Token (Jwt) là gì ?
Nếu đã từng làm việc với mô hình giao tiếp giữa client như web hay mobile, giao tiếp với server, chắc chắn bạn đã được tiếp xúc với khái niệm token.
Json Web Token hay Jwt là một chuỗi JSON object được định nghĩa theo chuẩn RFC 7519, 1 phương thức an toàn để mô tả chuỗi thông tin giữa 2 thành phần trong hệ thống.
Cách hoạt động của JWT
Trước khi vào cụ thể các thành phần của Jwt, chúng ta sẽ tìm hiểu trước xem cách mà nó hoạt động trong một hệ thống như thế nào .
Trên đây là mô hình cơ bản của việc giao tiếp giữa client và server.
- Client: đại diện bởi user, người sẽ thực thi các request
- Server: nơi nhận các request đến từ nguời dùng ( có thể từ web hay mobile app). Cụ thể trong mô hình này chúng ta sẽ có 2 server.
- Authen server: có thể hiểu đơn giản đây là server xác thực người dùng. Nó có nhiệm vụ xác thực xem bạn là ai khi bạn thực hiện đăng nhập vào hệ thống. Cần điều này đơn giản vì đây là 1 yếu tố để bảo mật cho hệ thống.
- Application server: server chính để xử lý các request đến từ người dùng.
Vậy jwt đóng vai trò gì trong mô hình này? jwt là 1 cách thức để server cấp quyền truy cập tài nguyên cho bạn. Nói nôm na, khi bạn đăng nhập hệ thống, server mới trả lời được câu hỏi "Bạn là ai?". Và nó sẽ phỉa có thêm 1 bước nữa để trả lời cho câu hỏi "Bạn có thể làm được gì trong hệ thống?" hay tức là phân quyền cho bạn. Jwt sẽ tham gia vào trong quá trình này.
Luồng hoạt động cụ thể:
- User đăng nhập vào bằng tài khoản.
- Authen Server sẽ xác thực xem thông tin đó đúng không. Nếu đúng sẽ tạo ra 1 chuỗi Jwt gắn với user và trả lại trong response.
- Sau khi nhận lại được response, client sẽ dùng jwt gắn vào header của request để có quyền truy cập các tài nguyên private.
- Application server sẽ xác thực. Nếu user đang truy cập tài nguyên public thì không cần check jwt. Còn ngược lại phải nhận được chuỗi jwt thỏa mãn mới cho phép truy cập.
Cấu trúc của jwt
Chúng ta sẽ tìm hiểu xem cấu trúc của 1 jwt như thế nào? Vì sao nó lại an toàn để có thể dùng trong quá trình authorization của hệ thống?
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
Đây là ví dụ về 1 chuỗi jwt. Trông khá 'ngầu' phải không ?
Tuy nhiên nếu tìm hiểu về cấu trúc của nó, chúng ta sẽ thấy chuỗi này khá đơn giản. Cấu trúc của nó như sau:
<base64-encoded header>.<base64-encoded payload>.<base64-encoded signature>
Header
{ "typ": "JWT", "alg": "HS256" }
Header cung cấp thông tin cơ bản về chuỗi Jwt.
- Typ: cho biết đây là 1 jwt
- Alg: cũng cấp tên thuật toán hashing đã dùng để mã hóa signature.
Payload
Đây là thành phần lưu trữ dữ liệu của jwt. Các data này còn được gọi là "claims" của jwt. Trong ví dụ này, authen server sẽ tạo jwt với thông tin của user gắn trong đó. Cụ thể là userID:
{
"userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
Lưu ý là ta hoàn toàn có thể lưu nhiều thông tin khác tùy thuộc vào bài toán cần xử lý. Trong ví dụ này ta đang tạo ra 1 claims riêng. Trong thực tế jwt còn hỗ trợ nhiều kiểu claims mặc đinh khác. Các bạn có thể tham khảo tại link sau: https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields
Signature
Chữ ký Signature là 1 chuỗi được mã hóa bằng thuật toán hashing. Tên thuật toán này sẽ được gắn vào phần header như trình bày ở trên.
Chúng ta sẽ xem pseudo code tạo ra signature:
1. data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
2. hashedData = hash( data, secret )
3. signature = base64urlEncode( hashedData )
Signature được ra bởi kết hợp header, payload và 1 đoạn mã secret. Chuỗi header và payload sẽ được encode bới base64, trước khi được dùng bởi thuật toán hashing với 1 chuỗi secret.
Sau khi hash xong, tiếp dùng base64url để enconde để tạo ra chuỗi signature cuối cùng.
Cuối cùng 3 thành phần header, payload và signature sẽ được nối với nhau thành chuỗi jwt hoàn chỉnh theo như cấu trúc
<base64-encoded header>.<base64-encoded payload>.<base64-encoded signature>
Hiểu đúng cơ chế của jwt
Sở dĩ mình bàn luận về vấn đề này bởi có thể nếu bạn chưa hiểu rõ được các khái niệm như 'encode' hay 'hashing' mà jwt dùng thì có thể bạn sẽ hiểu nhầm về nó.
Jwt không bảo mật được dữ liệu
Như mình trình bày ở trên. Trong phần payload của jwt chúng ta hoàn toàn có thể đặt vào những data mà chúng ta muốn trao đổi giữa các thành phần trong 1 hệ thống.
Bạn đang thấy jwt encode dữ liệu của chúng ta với base64url và nghĩ nó an toàn ? Bạn sẽ đặt 1 số dữ liệu nhạy cảm vào đó và cảm thấy vẫn yên tâm vì nó được mã hóa ?
Hoàn toàn sai nhé. Encoding không hề bảo mật dữ liệu của bạn. Nó chỉ giúp chuyển đổi format của dữ liệu để đảm bảo các bên có thể tiêu thụ và xử lý được dữ liệu nó. Có nghĩa rằng nếu bạn truyền dữ liệu nhạy cảm vào đây, tôi chỉ cần dùng đúng thuật toán của base64Url để có thể decode ngược lại và đánh cắp thông tin của bạn.
Với enconding, dữ liệu trong jwt không phải được bảo mật và an toàn truyệt đối.
Cơ chế xác thực jwt
Nếu theo dõi kĩ bài viết từ đầu, chắc bạn cũng đoán ra được chúng ta sẽ dùng cái gì để xác thực đâu là jwt hợp lệ. Nó chính là phần signature.
Phần này trước khi được encode bởi base64url, chúng ta thấy có thêm 1 bước là hashing (header + payload) kèm với 1 secret key. Ồ, nghe có key mật là thấy có vẻ bảo mật hơn rồi
Thực ra hashing với key mật này cũng không bảo vệ được phần data trong payload nhé.
Đơn giản về dùng hashing ở đây là để xác thực 1 chuỗi key duy nhất.
-
Cách thức: Với 1 chuỗi input nhất định, sau khi hashing luôn ra 1 output cố định. Tức ở đây, server sẽ nắm 1 chuỗi key mật. Hashing nó ra 1 output duy nhất và send cho client trong jwt.
-
Ý nghĩa: khi client đính kèm jwt này trong request. Server sẽ lấy ra phần singature này, so sánh với key mật của mình. Nếu trùng khớp thì đúng là client hợp lệ mà nó cho phép truy cập.
Hashing luôn đảm bảo 1 chuỗi secret key mà nó định nghĩa sẽ chỉ có 1 output sau khi hash.
Vậy là trên đây mình đã trình bày cơ bản về jwt. Hy vọng bài viết sẽ có ích cho các bạn. Thanks for reading!
All rights reserved