+14

Hiểu Rõ Luồng OAuth 2.0 qua các Hình Ảnh Động (GIFS)

Trong bài viết này Sydexa sẽ giúp bạn hiểu rõ luồng OAuth 2.0 qua các Hình Ảnh Động minh họa. Hãy chia sẻ bài viết này với những bạn bè đang muốn học về thiết kế hệ thống chịu tải cao bạn nha 😍


Chúng mình có tạo Group cho các bạn cùng chia sẻ và học hỏi về thiết kế hệ thống nha 😄😄😄

Các bạn tham gia để gây dựng cộng đồng System Design Việt Nam thật lớn mạnh nhé 😍😍😍

Cộng Đồng System Design Việt Nam: https://www.facebook.com/groups/sydexa

Kênh TikTok: https://www.tiktok.com/@sydexa.com


Bạn đang đau đầu vì muốn lấy danh sách bạn bè từ App B sang App A mà không muốn người dùng phải nhập thủ công từng người một, tốn thời gian và công sức? Hay App B không có tính năng export khiến việc cập nhật danh sách bạn bè trở nên rắc rối? Hay không muốn cấp thông tin đăng nhập của App B cho App A vì lí do bảo mật?

OAuth chính là "chìa khóa" giải mã bí ẩn này! OAuth cho phép App A truy cập an toàn vào danh sách bạn bè của App B mà không cần thu thập username, password của người dùng.

Trước hết, OAuth là gì?

Với ví dụ bên trên, ta có thể hiểu OAuth (Open Authorization) cho phép các trang web hoặc ứng dụng bên thứ ba truy cập vào dữ liệu của người dùng mà không yêu cầu họ chia sẻ thông tin đăng nhập của mình (username, password) . Người dùng quyết định những tài nguyên nào một ứng dụng có thể truy cập và hạn chế quyền truy cập tương ứng.

OAuth là từ ghép của O (Open)Auth tượng trưng cho:

  • Authentication: xác thực người dùng.
  • Authorization: cấp quyền truy cập đến tài nguyên mà người dùng hiện đang nắm giữ. image.png
    Ví dụ về việc đăng nhập sử dụng mạng xã hội, sử dụng giao thức OAth 2.0

Các thuật ngữ chính

Trước khi đi sâu vào từng luồng, ta tìm hiểu một số thuật ngữ chính trong OAuth.

Term Description
Client 📦 Là ứng dụng bên thứ 3 muốn truy cập vào tài nguyên
Resource Owner 👤 Là người sở hữu tài nguyên cần truy cập, thường được hiểu là end-user. Nó cũng có thể là một machine
Resource 🖼 Có thể là ảnh, dữ liệu được tiếp cận thông qua API và các tài nguyên khác
Resource Server 📚 Máy chủ chứa các tài nguyên được bảo vệ. Thông thường, đó là một API Server cung cấp các tài nguyên nếu có một token hợp lệ được cung cấp. Ví dụ như Facebook, Google
Authorization Server 🛡 Máy chủ chịu trách nhiệm cho việc uỷ quyền client và cấp phát các access token cho client.
User-Agent 🌐 Trình duyệt hoặc ứng dụng di động thông qua đó Resource Owner giao tiếp với Authorization Server.
Access Token 🔑 Một token được cấp sau quá trình ủy quyền thành công. Một access token có thể được lấy để sử dụng cho một tập hợp các quyền và có một thời gian tồn tại đã được xác định trước, hết thời gian này thì nó hết hạn.
Refresh Token 🔄 Một loại đặc biệt của token có thể được sử dụng để làm mới lại Access Token.


Để dễ hiểu các khái niệm trừu tượng phía trên thì ta sẽ xem qua một ví dụ sau nhé!

Một end-user (Resource Owner 👤) cấp quyền truy cập truy cập cho một dịch vụ in ấn (Client 📦) vào ảnh của họ (Resource 🖼) được lưu trữ trong một dịch vụ chia sẻ ảnh (Resource Server 📚) mà không cần chia sẻ username và password (thông tin đăng nhập). Thay vào đó, họ xác thực trực tiếp với một máy chủ được tin cậy bởi dịch vụ chia sẻ ảnh (Authorization Server 🛡), máy chủ này sẽ cấp giấy phép cho phép truy cập dữ liệu trong thời gian giới hạn cho dịch vụ in ấn (Access Token 🔑).

Cần lưu ý một điều sau: Client phải được đăng ký trước trong Authorization Server. Kết quả trả về một Client ID. Một client secret cũng có thể được tạo ra tùy thuộc vào bối cảnh. Secret này chỉ được biết đến bởi Authorization ServerỨng dụng.

Được rồi, đủ lý thuyết! Ta sẽ quan sát các hình ảnh động dưới đây để hiểu các luồng hoạt động của OAuth 2.0

“A picture is worth 1024 words”

Các luồng trong OAuth 2.0

  1. Authorization Code Grant
  2. Authorization Code Grant with PKCE
    • Code Transformation Method (CM) - Meet SHA256
    • Code verifier (CV) & Code Challenge (CC)
  3. Client Credentials Grant
  4. Resource Owner Password Credentials Grant
  5. Implicit Grant

1. Authorization Code Grant flow

Đây là một quy trình xác thực phổ biến dựa trên trình duyệt cho các ứng dụng Web và di động. Bạn có thể liên kết trực tiếp với ví dụ được đề cập ở trên. Trong biểu đồ dưới đây, quá trình bắt đầu ở bước điều hướng Client, chuyển người dùng đến trang đăng nhập.

https://res.cloudinary.com/practicaldev/image/fetch/s--AHu-wF84--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/2j7kqc7qabtfpl250jf2.gif

Quy trình này được tối ưu hóa cho các confidential clients - là các ứng dụng bảo đảm tính bảo mật cho client secret. Điều này là do nột phần của quy trình này diễn ra trên front-channel (cho đến khi authorization code được nhận) . Như trên hình, bước trao đổi access_token diễn ra một cách bí mật thông qua back-channel (giao tiếp giữa các máy chủ).

⚠️ Vậy nếu ứng dụng không đảm bảo được tính bảo mật cho client secret thì sẽ như thế nào? Tức là đối với public client thì sẽ xử lí như thế nào?

2. Authorization Code Grant with PKCE

Trong quy trình trên, các public clients đặt ra một số lo ngại về bảo mật. Đó là các ứng dụng single-page JS hoặc các ứng dụng native mobile, không thể che giấu được client_secret vì toàn bộ mã nguồn có thể truy cập (qua công cụ Developer Tools hoặc App Decompilation).

Để giải quyết vấn đề này, Authorization Code Grant Flow sử dụng Proof Key for Code Exchange (PKCE). Điều này cho phép tạo ra một mã bí mật tại thời điểm chạy mà có thể được xác minh bởi Authorization Server. Vậy mã đó là gì? Nó hoạt động như thế nào?

2.1. Transformations - Meet SHA256

Cơ bản, client tạo ra một chuỗi ngẫu nhiên được gọi là Code Verifier (CV). Một Code transformation method (CM) được tác động vào CV để tạo ra một Code Challenge (CC). Hiện nay, có hai phương pháp transformation là plain hoặc S256 (SHA-256).

https://res.cloudinary.com/practicaldev/image/fetch/s--B_piWcqc--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/tw9nu7l1yufx3bczy7fi.gif

Trong phương pháp biến đổi plain, CC sẽ là CV. Điều này không được khuyến khích vì những lý do bảo mật, S256 được khuyên dùng. SHA256 là một hàm băm. Nó nhận đầu vào có độ dài bất kì và đưa ra một chuỗi có độ dài cố định. Tuy nhiên, có những đặc điểm đặc biệt của chuỗi xuất ra này:

  • Chuỗi này là duy nhất đối với dữ liệu đầu vào và bất kỳ thay đổi nào trong dữ liệu đầu vào cũng sẽ dẫn đến một chuỗi xuất ra khác! Có thể nói, đó là một signature của dữ liệu đầu vào.
  • Dữ liệu đầu vào không thể khôi phục từ chuỗi giúp nó có tính một chiều (tức là từ CC có thể ra CV chiều ngược lại là không thể).

2.2. Các tạo ra CC từ CV?

https://res.cloudinary.com/practicaldev/image/fetch/s--HBGdHaJo--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/tfuwug010zprz84p702o.gif

Hình động trên biểu diễn việc tạo ra CC từ CV. Trong trường hợp này, vì SHA256 được áp dụng vào CV do đó CV không thể được tạo ra từ CC (Do đây là một phép biến đổi một chiều). Chỉ có thể tạo ra CC từ CV (trong trường hợp ta đã biết phương pháp biến đổi là gì - ở đây là S256).

PKCE Flow

Vậy đến đây ta đã hiểu CC, CV, CM và cách biến đổi từu CV thành CC, bây giờ ta sẽ xem xét toàn bộ luồng này.

https://res.cloudinary.com/practicaldev/image/fetch/s--piE2bmSb--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/odkf14kzlb5gcbvrmuvx.gif

Hầu hết các phần đều tương tự với luồng đầu tiên ngoại trừ việc CV và CC được tạo ra trước sẽ thay thế cho client_secret. CV và CC được tạo ra ngay từ đầu luồng. Ban đầu, chỉ CC và CM được truyền để nhận một authorization code. Khi authorization code được nhận, CV cũng được gửi để authorization server kiểm tra và client nhận về access token.

Authorization server xác nhận bằng cách áp dụng phương pháp biến đổi (CM - SHA256) trên CV nhận được và so sánh nó với CC đã nhận trước đó. Nếu nó khớp, một access token sẽ được cung cấp! Ngay cả khi ai đó lấy được authorization code, họ sẽ không có CV. Nhờ vào tính chất của hàm một chiều, một CV không thể được khôi phục từ CC. Ngoài ra, CV không thể được tìm thấy từ mã nguồn hoặc thông qua giải mã vì nó chỉ được tạo ra trong thời gian chạy!

3. Client Credentials Grant flow

Trong các luồng trên, resource owner (tức là người dùng) phải cung cấp sự đồng ý. Cũng có thể có các tình huống mà sự ủy quyền của người dùng không cần thiết. Hãy nghĩ đến giao tiếp giữa máy với máy (hay giữa các ứng dụng). Trong trường hợp này, Client là bí mật và các ứng dụng cần tự hành động thay cho người dùng.

https://res.cloudinary.com/practicaldev/image/fetch/s--4R62NCHI--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/gp4n79x84xujj8mn625w.gif

Đây cũng chính là luồng đơn giản nhất trong tất cả các luồng.

4. Resource Owner Password Credentials Grant flow

Luồng này chỉ nên được sử dụng khi có mức độ tin cậy cao giữa Resource OwnerClient. Như trong hình bạn có thể thấy, ban đầu, username & password được nhận từ R.O và được sử dụng để lấy access_token. Thông tin username & password sẽ được loại bỏ sau khi access token được nhận.

https://res.cloudinary.com/practicaldev/image/fetch/s--SzG-dSQZ--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/6hsfukc7f4rnopbsy04f.gif

Luồng này không được khuyến nghị cho các ứng dụng hiện đại. Nó mang lại rủi ro cao hơn so với các luồng khác. Đồng thời nó va chạm phải password anti-pattern điều mà OAuth muốn tránh đầu tiên!

5. Implicit Grant flow

Luồng này không còn được khuyên dùng! Implicit grant được coi là một lựa chọn thay thế cho Authorization Code Grant cho các public-client. Như bạn có thể nhận thấy, public-client không chứa client_secret và không có back-channel liên quan. Trong thực tế, access token được nhận ngay sau khi có sự đồng ý của người dùng.

https://res.cloudinary.com/practicaldev/image/fetch/s--29o38GP4--/c_limit,f_auto,fl_progressive,q_66,w_880/https://dev-to-uploads.s3.amazonaws.com/i/90t3te63144tcdven41w.gif

Tuy nhiên, access token được truyền trong phần fragment URL (Bắt đầu với #). Phần fragment được truy cập bởi một script được tải trong phía frontend. Access token sẽ được lấy ra theo cách này và các bước tiếp theo được thực hiện tương tự các luồng trên để lấy tài nguyên. Dễ dàng có thể thấy, luồng này dễ bị rò rỉ access token và bị tấn công.

Lời khuyên: Bạn nên xem xét sử dụng Authorization Code Grant hoặc bất cứ luồng phù hợp nào khác thay cho implicit


Sydexa.com xin hẹn gặp lại các bạn ở các bài viết thú vị hơn nha

Lời nhắn

Chúng mình có tạo Group cho các bạn cùng chia sẻ và học hỏi về thiết kế hệ thống nha 😄😄😄

Các bạn tham gia để gây dựng cộng đồng System Design Việt Nam thật lớn mạnh nhé 😍😍😍

Cộng Đồng System Design Việt Nam: https://www.facebook.com/groups/sydexa


All rights reserved

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í