+10

Cách triển khai RefreshToken và AccessToken P1: Đừng lưu tất cả phiên của người dùng

Bài viết có có nội dung cấm, chỉ đọc nếu bạn muốn logout jwt 😦

Dùng JWT đi thời nào rồi còn dùng session nữa ba...

Yeah, câu chuyện muôn thuở của newbie khi mới code phần authentication, every where... từ các group tới các khoá học basic nodejs, resfulapi, mongodb & expressjs vân vân và mây mây, chỗ nào cũng nhận được lời khuyên rằng dùng jwt thay cho session, sẽ giảm tải được cho server vì trạng thái của người dùng sẽ được lưu ở client thay vì server bala bala.... Nhưng mọi chuyện đâu chỉ đơn giản là sign state của user rồi quăng cho client là được. Mọi rắc rối mới chỉ bắt đầu.

First things first

Lời nói đầu

Mình là Đức Master - dev của LmssPlus, bữa nay mới được khai thông mấy cái lặt vặt về hệ thống Authentication và Authorization nên ngứa ngáy tay chân viết cái blog để hệ thống lại chút. Tiện bày cho các bạn newbie giống mình dùng jwt chưa được "chuẩn chỉ" cho lắm cách setup hệ thống cho mượt. Mình cũng không phải chuyên môn hay cao siêu gì, học được gì hay ho thì chia sẻ với các bạn thôi, có gì sai sót mong mọi người góp ý.

Session hoạt động như thế nào?

Giả dụ trong lãnh địa của mình có 5 khu, 1 khu nấu ăn, 1 khu wc, 1 khu phòng nghỉ ngơi thư giãn, 1 khu để giữ xe, và 1 tầng hầm (để nhốt các bé loli). Chuyện đáng nói là ông bảo vệ đòi xuống tầng hầm chơi với các bé loli, mình thấy không yên tâm lắm nên đuổi việc rồi nhờ vợ thuê cho hẳn 1 đội bảo vệ chuyên nghiệp siêu cấp vip pro. Gòy nay đi chơi về nhà có ông bảo vệ mới toanh đứng trước nhà không cho mình vô. Ông đòi mình xuất trình usernamepassword, rồi ông ý tìm trong sổ user thấy oke mới viết vào sổ sessioncác quyền của mình, mình có chụp trộm được đây:

Rồi ông ý đưa mình cái mã chúa-tể-lãnh-địa-random123 bảo mình lần sau có vô thì không cần đọc pass, cứ đưa cái mã đó vô là được. Mình cũng ậm ừ không hiểu lắm cơ mà cũng được. Làm ăn thế này thì không lo 113 bắt rồi hehe.

Vừa nãy có bạn X vào chơi bị ông bảo vệ lại chặn lại, nó mới quăng cho ông bảo vệ cái mã bạn-chúa-tể-random2233 (hồi sáng nó cấp username/pass nên được đưa cho mã này). Ông bảo vệ nhìn cái mã, lục lọi trong đống giấy, tìm mãi mới thấy tờ có nội dung như thế này:

Vậy là bạn X này được xài khu WC và phòng ngủ 2, chỉ được vô 2 khu đó thôi, vô chỗ khác là bị các chú bảo vệ pằng pằng.

Và đó chính là cách session hoạt động. Khi client tạo 1 request login tới server, server sẽ tìm trong sổ user coi có hợp lệ không, nếu oke thì lấy các quyền mà user đó có, rồi tạo 1 session lưu ở server và trả về cho client 1 cookie (chứa session id (không trùng lặp)). Với mỗi request, client sẽ cầm theo cookie, server sẽ dựa vào id trong đó để tìm trong sổ session, coi cái nào khớp thì coi có quyền gì mà xử lí, không có thì bắt login lại.

Jwt là gì?

Haizz, mọi chuyện vẫn ổn, nhưng chuyện mình vừa kể là câu chuyện cách đây 1 năm rồi. Sau đó mình làm ăn phát đạt, có cả chục ngàn khách ghé thăm. Mấy ông bảo vệ lưu đám giấy nhiều quá, không có chỗ mà chứa nữa 😦. Vì cứ một người lại 1 tờ lưu như trên ấy, hic. Thế là mình mới nhờ các mỗi quan hệ của mình và tìm được 1 đội cảnh vệ tên là JWT, lúc đó nghe người ta giới thiệu rằng đội bảo vệ này giải quyết được vấn để lưu quá nhiều giấy, cách giải quyết của họ là: không lưu giấy, oh wow...

Lần đầu, ông ý cũng đòi mình xuất trình usernamepassword rồi ông ý tra trong sổ user, cơ mà lần này thay vì ông ý viết vào sổ session và đưa cho mình 1 cãi mã ngắn ngắn thì ông ý đưa cho mình 1 cãi mã dài đoằng, mình có chụp cho bạn coi nè :

Oh, vậy là ông ý đưa cho mình 1 giấy uỷ quyền gồm quyền của mình, trên đó chữ kí của nóc nhà (vợ mình) và ngày hết hạn. Vậy là mình cầm 1 tờ giấy giả (không có chữ kí hợp lệ) hay 1 tờ giấy đã quá hạn sẽ không được. Còn ngược lại các tờ giấy hợp lệ thì cứ theo nội dung trên tờ giấy mà làm. Mình cầm tờ này đi tới khu vui chơi, ông bảo vệ trước khu vui chơi nhìn tờ giấy hợp lệ liền cho mình vô mà không phải tra bất cứ tài liệu, sổ sách gì, chỉ cần giấy uỷ quyền được kí và chưa hết hạn là được.

Vậy là bây giờ theo cách này không cần phải lưu bất cứ giấy tờ gì nữa, không phải lo không có chỗ lưu giấy tờ rồi (tiết kiệm tài nguyên cho server).

Đó chính là cách jwt hoạt động. Không lưu session, cấp cho người dùng 1 tờ giấy uỷ quyền (token), trên đó có thông tin/quyền user được phép, có chữ kí và ngày hết hạn. Mỗi lần truy cập vào đâu ông bảo vệ không cần tra cứu sổ sách gì cả, cứ nhìn giấy uỷ quyền hợp lệ là cho vô.

Chốt hạ

Session Jwt
Cần database hoặc session store (trong ram) để lưu session data Không cần db hoặc ram để lưu session data
Tìm trong session store hoặc database với mỗi request Session data đã được gắn ở trong token, chỉ cần check chữ kí và hạn
Khó mở rộng và tốn tài nguyên để lưu trữ Không tốn tài nguyên lưu trữ (*) và dễ mở rộng
Cookie chứa SessionID (unique) random, chỉ có sessionID, không có thông tin khác Có các thông tin user/quyền của user được đặt trong token
Thu hồi bằng cách xoá session Một khi đã kí không thể thu hồi theo cách thông thường
Thay đổi quyền truy cập bằng cách thay đổi session Một khi đã kí không thể thu hồi theo cách thông thường

Ác mộng mới chỉ bắt đầu

Cứ tưởng tới đó là cuộc sống của mình trở lên hạnh phúc rồi, nhưng thật không ngờ trong những người khách hàng vào khu tầng hầm loli của mình lại có người là công an mật. Rồi giờ làm sao để block người khách là công an mật này? Người ta ra vào có tờ giấy uỷ quyền hợp lệ (đã được kí và không hết hạn), bảo vệ thì cứ check sign hợp lệ là cho vào. Vậy phải làm sao đây 😦

Mình cùng đội bảo vệ giải quyết vấn đề này thế nào mời các bạn đón xem phần 2


All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@ThanhBao
thg 6 24, 2022 2:38 CH

Dự đoán phần 2:

  • Cấp giấy thông hành cho ông A xong, ông vô tình đánh rơi tại bãi giữ xe, ông B nhặt được vậy là ông B cầm tờ giấy đó giả danh ông A qua mặt được bảo vệ (User A authen thành công ➜ server response token ➜ User A bị Man-in-the-middle attack, do User A bất cẩn làm token rơi vào tay hacker ➜ hacker chiếm quyền truy cập account của user A mà server không hề hay biết)
  • Ông A đang chơi đùa trong khu vui chơi, đột nhiên giấy thông hành hết hạn lập tức bảo vệ lôi đầu ông A ra ngoài cổng hỏi username, password mới cho vào lại làm ông A mất hứng ( user A đang truy cập các private API, đột nhiên token expired, màn hình đột ngột bị rediect sang trang login vì server response 403).
  • Ông A đi chơi quỵt tiền, giám đốc phát lệnh cấm ông A vĩnh viễn nhưng ông A vẫn cứ tới và đưa giấy cho bảo vệ, bảo vệ thấy giấy hợp lệ và "đây đúng là chữ ký của mình mà" thế là cho ông mà không biết ông đã bị từ chối phục vụ (server chưa cài đặt cơ chế hủy token, phía database thì account user A đã bị ban, nhưng token vẫn đang lưu rải rác tại các client (desktop app, mobile app, web, server khác, ...), client vẫn cứ gửi token, server encode payload token thấy vẫn còn hạn sử dụng, phần mã hash chữ ký vẫn hợp lệ ➜ user vẫn author thành công)
Avatar
@ducmaster
thg 6 24, 2022 3:48 CH

Chết, máy quay nén a để đâu...

Avatar
@huanhm
thg 7 15, 2022 4:26 SA

style viết này hay đọc dễ hiểu, tựa tựa bác minh monmen. thanks bạn nhiều

Avatar
@tran.dai.son
thg 7 15, 2022 11:43 CH

Cách logout jwt (viết ra đây để xem cách làm có khác gì với chủ thread ko)

  • Khi gọi API logout thì lưu token đã logout vào blacklist.
  • Trong các API được authen, khi có request đến, check token có nằm trong blacklist hay không, nếu có thì coi như unauthorize.
  • Bài toán đặt ra là lưu blacklist ở đâu để việc đọc token đảm bảo được về mặt hiệu suất khi mà tần số gọi API dày đặc như vậy? Câu trả lời là lưu trong redis. Mặc khác vì jwt token nó có thời hạn sống ngắn, nên hoàn toàn có thể clean up dữ liệu, xoá các token đã thực sự hết hạn trong redis.
Avatar
+10
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí