OAuth 2.0 là gì: Chuẩn ủy quyền và bảo vệ API

Sơ đồ trình tự Authorization Code Grant của OAuth 2.0 từ chủ tài nguyên tới truy cập API

OAuth 2.0 là gì và tại sao mọi ứng dụng hiện đại đều phụ thuộc vào nó? Nếu bạn đăng nhập Google, Facebook hay GitHub bằng tài khoản sẵn có, bạn đang dùng OAuth 2.0 mà không hề biết. Cơ chế này cho phép bạn trao quyền truy cập hạn chế vào tài khoản của mình cho ứng dụng khác, mà không bao giờ phải đưa mật khẩu ra khỏi trình duyệt.

Bài viết sau phân tích các vai trò, các grant type phổ biến, vòng đời access token và refresh token, cùng những lỗ hổng kinh điển như CSRF trong luồng authorization mà nhiều đội vẫn mắc phải.

Sơ đồ trình tự Authorization Code Grant của OAuth 2.0 từ chủ tài nguyên tới truy cập API

OAuth 2.0 là gì

OAuth 2.0 là gì — đó là một chuẩn mã nguồn mở về ủy quyền, được phát triển bởi nhóm kỹ thuật OAuth và xuất bản tháng 10 năm 2012 dưới dạng RFC 6749. Chữ O trong OAuth là viết tắt của Open Authorization. Cần làm rõ một điểm hay gây hiểu nhầm: OAuth không phải là giao thức xác thực, nó là giao thức ủy quyền cho biết bạn là ai, không phải để xác minh bạn là ai.

Trước OAuth, việc cho ứng dụng bên thứ ba đọc dữ liệu từ dịch vụ khác buộc phải trao tài khoản và mật khẩu cho nó. Đó là mô hình “chốt trường” chung mà thuật ngữ antifragility gọi là credential sharing — rủi ro lớn. OAuth thay bằng luồng bốn bước trong đó người dùng chủ động cấp quyền, và mật khẩu không bao giờ rời khỏi máy chủ chủ lực.

Bốn vai trò trong OAuth 2.0

Vai trò Ý nghĩa Ví dụ
Resource Owner Chủ sở hữu dữ liệu, là người dùng cuối Bạn
Client Ứng dụng muốn truy cập dữ liệu Ứng dụng di động, website
Authorization Server Xác thực và cấp token Google, Keycloak
Resource Server Nơi lưu và bảo vệ API API của Google Calendar

Client và Resource Server có thể nằm trên cùng một hệ thống. Trong các bộ SDK như next-auth, bạn thường chỉ cấu hình một authorization server bên ngoài rồi dùng access token truy cập API của nhà cung cấp.

Luồng Authorization Code là lựa chọn mặc định

Đây là luồng được khuyến nghị cho mọi trường hợp có backend, vì access token không bao giờ đi qua trình duyệt với mô hình cơ bản. Trình tự như sau:

  1. Authorize — ứng dụng chuyển người dùng tới trang đăng nhập của authorization server kèm các tham số client_id, redirect_uri, scope và state.
  2. Consent — người dùng đăng nhập và chọn quyền muốn cấp.
  3. Authorization code — server chuyển hướng về redirect_uri kèm mã ngắn hạn, thường chỉ sống vài chục giây và dùng đúng một lần.
  4. Exchange — backend của ứng dụng trao code lấy access token qua kênh bảo mật bằng client_secret.
  5. Access API — ứng dụng gọi API kèm header Authorization: Bearer <token>.

Ý tưởng cốt lõi: authorization code là thứ vô nghĩa nếu bị đánh cắp, vì kẻ trộm không có client_secret để đổi nó lấy token. Người dùng cũng không bao giờ phải dán token vào trang web lạ.

Sơ đồ luồng OAuth 2.0 có PKCE với mã xác minh đổi lấy access token

PKCE: giải pháp cho ứng dụng không còn client secret

Các ứng dụng SPA và mobile không thể giữ bí mật an toàn — bất kỳ ai mở DevTools đều thấy. Đó là lý do RFC 8252 sinh ra Proof Key for Code Exchange.

Ứng dụng tạo một chuỗi ngẫu nhiên gọi là code_verifier, gửi bản băm SHA-256 của nó làm code_challenge cùng method S256. Khi đổi code lấy token, ứng dụng gửi cả code_verifier gốc. Server chỉ cấp token nếu hash khớp với challenge đã nhận. Kẻ trộm authorization code không có verifier nên vô hiệu. PKCE giờ đã trở thành bắt buộc theo OAuth 2.0 Security Best Current Practice và nên dùng với cả authorization code lẫn cả implicit grant.

Các grant type phổ biến

Grant type Dùng cho Có client secret?
Authorization Code Ứng dụng web có backend Có
Authorization Code + PKCE SPA, mobile, desktop Không
Client Credentials Dịch vụ gọi dịch vụ khác, máy máy Có, bắt buộc
Device Code TV, thiết bị không nhập được Không
Refresh Token Lấy token mới khi access token hết hạn Có (nếu confidential client)

Implicit grant (token trả thẳng trong URL) đã bị loại khỏi đặc tả và không nên dùng cho dự án mới, vì access token lọt vào lịch sử trình duyệt và log máy chủ.

Sơ đồ tổng quan các vai trò resource owner, client, authorization server và resource server

Access token, refresh token và scope

Access token là vé vào cửa, thường sống 5 phút đến 1 giờ, dạng JWT hoặc chuỗi mờ. Nó được gửi kèm mỗi lần gọi API.

Refresh token là chìa khoá dự phòng, có thể sống vài tuần tới vài tháng, chỉ dùng để đổi lấy access token mới. Vì nó lâu hạn và quyền lớn hơn, bảo mật phải chặt hơn: lưu trong cookie HttpOnly và Secure thay vì localStorage, hỗ trợ refresh token rotation — mỗi lần dùng thì cấp token mới và vô hiệu token cũ, phát hiện được trộm token khi kẻ trộm dùng token đã bị thu hồi.

Scope giới hạn phạm vi truy cập, ví dụ chỉ read:email chứ không đụng tới write:calendar. Nguyên tắc đặc quyền tối thiểu trong OAuth cũng chính là nguyên tắc này: chỉ xin đúng những gì tính năng cần, và tách từng chức năng thành scope riêng để người dùng kiểm soát tinh vi.

Tham số bảo mật không được bỏ qua

  • redirect_uri phải được so khớp chính xác với giá trị đã đăng ký, không dùng so khớp lỏng hay ký tự đại diện.
  • state ngẫu nhiên và kiểm tra lại khi quay về — đây là cơ chế chống CSRF và chống tấn công authorization code injection.
  • Luôn dùng HTTPS, không bao giờ truyền token qua kênh không mã hoá.
  • Token lưu ở phía máy chủ khi có thể, tránh đưa vào trình duyệt.
  • Kiểm tra chữ ký và thời hạn của token nếu dùng JWT, kèm kiểm tra thuật toán, issuer và audience.
  • Đặt thời hạn ngắn cho mọi token thay vì cấp token vĩnh viễn.

Liên hệ với OpenID Connect

OAuth nói về ủy quyền, không cung cấp danh tính. Khi bạn cần biết người dùng là ai, chuẩn bổ sung là OpenID Connect, xây trên OAuth và bổ sung id token chứa thông tin định danh, cùng endpoint /.well-known/openid-configuration để ứng dụng tự khám phá cấu hình. Đăng nhập Google hay Facebook chính là OIDC, không đơn thuần là OAuth. Nhiều đội vẫn dùng sai OAuth để xác thực và tạo ra lỗ hổng không thể vá.

Kết luận

Trả lời lại câu hỏi đầu bài: OAuth 2.0 là gì — đó là chuẩn ủy quyền cho phép ứng dụng khác truy cập tài nguyên hạn chế mà không cần trao mật khẩu. Nếu triển khai đúng, nó giải quyết một bài toán bảo mật thật sự khó: chia sẻ quyền hạn mà vẫn giữ được ranh giới tin cậy. Ngược lại, cấu hình sai thiếu state hay bỏ PKCE sẽ mở ra những lỗ hổng tấn công ở tần số đáng báo động.

Đọc bản đặc tả gốc tại RFC 6749 – The OAuth 2.0 Authorization Framework. Với phần PKCE, xem RFC 7636 – Proof Key for Code Exchange. Danh sách các lỗ hổng đã biết được duy trì công khai trong RFC 6819 – OAuth 2.0 Security Considerations, và bản khuyến nghị cập nhật nhất nằm ở OAuth 2.0 Security Best Current Practice — tài liệu này đã chính thức loại bỏ luồng implicit và password grant.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Nginx là gì: Reverse proxy và load balancer phổ biến nhất

Nginx (đọc là “engine-x”) là một máy chủ web mã nguồn mở, reverse proxy và load balancer phổ biến nhất thế giới. Nhờ kiến trúc bất đồng bộ dựa trên…

Xem thêm

Ẩn dữ liệu nhạy cảm trong commit Git: Công cụ và quy trình đúng

Ẩn dữ liệu nhạy cảm trong commit Git là một trong những sai lầm phổ biến nhất của lập trình viên: đẩy API key, mật khẩu hoặc token lên kho…

Xem thêm

TOTP là gì? Xác thực hai lớp bảo vệ tài khoản an toàn hơn SMS

TOTP (Time-based One-Time Password) là thuật toán sinh mật khẩu dùng một lần dựa trên thời gian hiện tại, được chuẩn hoá thành RFC 6238 của IETF. Đây là xương…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất