OpenID Connect
翻译
原文:https://portswigger.net/web-security/oauth/openid
- name: 翻译
desc: 原文:https://portswigger.net/web-security/oauth/openid
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 1OpenID Connect
在本节中,我们将提供有关 OpenID Connect 的一些关键背景知识,以帮助你了解我们将要介绍的一些漏洞 (opens new window)。如果你不熟悉 OAuth 和 OpenID Connect,我们建议你在尝试完成 OpenID 的实验之前阅读本章节。
# 2OpenID Connect是什么?
OpenID Connect 扩展了 OAuth 协议,提供了一个位于基本 OAuth 实现 (opens new window)之上的专用身份和身份验证层。它添加了一些简单的功能,可以更好地支持 OAuth 在身份验证场景中的实现。
最初,OAuth 在设计时并未考虑到身份验证;它最初是希望在 应用程序之间 委派特定的资源授权。然而,许多网站开始自定义 OAuth 并将其作为身份验证机制。为了实现这一点,这些网站通常会请求一些基本访问权限,例如对用户数据的读权限,如果他们被成功授予此权限,则说明用户在 OAuth 提供商一侧对自己进行了身份验证。
这些 OAuth 身份验证 (opens new window)机制看起来容易实现,但远非理想。首先,客户端应用程序无法知道何时、何地以及如何对用户进行身份验证。这些实现中的每一个功能模块,都可以是某种自定义的解决方案,因此也没有为该目的而设计的一种标准方法。为了正确地支持 OAuth,客户端应用程序必须为每一个提供商,分别配置单独的 OAuth 机制,因为每个提供商都有不同的端点、唯一的作用域集合等差异性。
OpenID Connect 通过添加标准化的、与身份相关的功能来解决以上绝大多数问题,使通过 OAuth 实现的身份验证能够以更可靠和统一的方式工作。
# 3OpenID Connect如何工作?
OpenID Connect 完美嵌入到标准的 OAuth 流 (opens new window)中。从客户端应用程序的角度来看,主要的区别在于 - 有一组额外的标准化作用域,这些作用域对所有提供商都是相同的,还有一个额外的响应类型:id_token
。
# 3.1OpenID Connect角色
OpenID Connect 的角色与标准 OAuth 的角色基本相同。主要区别在于 - 该规范使用的术语略有不同。
- 依赖方 - 请求对用户进行身份验证的应用程序。这是 OAuth 客户端应用程序的同义词。
- 最终用户 - 正在进行身份验证的用户。这是 OAuth 资源所有者的同义词。
- OpenID 提供商 - 一个配置为支持 OpenID Connect 的 OAuth 服务。
# 3.2OpenID Connect声明与作用域
术语 “声明” 指的是资源服务器上的一些键值对,用于表示跟用户相关的信息。一个声明的例子:"family_name":"Montoya"
。
在基本 OAuth 服务中,每个提供商都会设置自定义的作用域,与基本 OAuth 不同,所有的 OpenID Connect 服务都使用一组相同的作用域集合。若要使用 OpenID Connect,客户端应用程序必须在授权请求中通过openid
来指定作用域,在其中可以包含一个或多个其他标准范围:
profile
email
address
phone
在 OpenID 规范中定义了有关于用户 “读访问权限” 的声明子集 ,这些权限对应着相关的作用域。例如,在请求作用域openid profile
时,将会把与用户身份相关的一系列声明(例如family_name
、given_name
、birth_date
等)的读访问权限授予给客户端应用程序。
# 3.3ID token
OpenID Connect 提供的另一个主要附加功能是id_token
响应类型。它会返回经过 “JSON web signature”(JWS)签名的 “JSON web token”(JWT)。JWT 中包含初始请求的作用域声明列表,同时它还包含有关于用户上次通过 OAuth 服务进行身份验证的方式和时间信息。客户端应用程序可以使用它,来确定用户是否已经通过身份验证。
使用id_token
的一个主要好处,可以减少客户端应用程序和 OAuth 服务之间发送的请求数,从而提供更好的整体性能。不需要先获取访问令牌,然后再单独请求用户数据,而是在用户完成身份验证时,同步将包含此数据的 ID 令牌发送给客户端应用程序。
与基本 OAuth 中的情况不同,ID 令牌传输时的数据完整性基于 JWT 加密签名,而不是简单地依赖于可信通道。因此,使用 ID 令牌可能有助于防范某些中间人攻击。然而,用于验证签名的加密密钥也会通过同一网络通道传输(通常在/.well-known/jwks.json
上公开),这使得某些攻击仍然成为可能。
请注意,OAuth 支持多种响应类型,因此客户端应用程序在发送授权请求时,可以同时发送基本 OAuth 的响应类型和 OpenID Connect 的id_token
响应类型:
response_type=id_token token
response_type=id_token code
2
在这种情况下,ID 令牌和授权码 / 访问令牌,将会同时发送到客户端应用程序。
# 4识别OpenID Connect
如果客户端应用程序正在使用 OpenID connect,则从授权请求中可以明显看出这一点。最万无一失的检查方法是查找强制性的openid
范围。
即使登录过程最初似乎没有使用 OpenID Connect,但仍然值得你去检查 OAuth 服务是否支持它。你可以简单地尝试添加openid
作用域或将响应类型更改为id_token
,并观察这是否会导致错误。
与基本 OAuth 相同,查看 OAuth 提供商的文档也是一个好主意,看看其中是否有任何关于其 OpenID Connect 支持的有用信息。你还可以从标准端点/.well-known/openid-configuration
访问其配置文件。
# 5OpenID Connect漏洞
OpenID Connect 的规范比基本 OAuth 规范要严格得多,这意味着,其通常不太可能存在明显缺陷的实现。但转念一想,OpenID Connect 只是位于 OAuth 之上的一层,因此客户端应用程序或 OAuth 服务仍然容易受到我们之前看到的一些基于 OAuth 的攻击。事实上,你可能已经注意到,我们所有的 OAuth 身份验证实验室 (opens new window)也都使用了 OpenID Connect。
在本节中,我们将介绍 OpenID Connect 的一些额外功能引入的其他漏洞。
# 5.1不受保护的动态客户端注册
OpenID 规范概述了一种标准化方法,允许客户端应用程序向 OpenID 提供商注册。如果支持动态客户端注册,则客户端应用程序可以向专用的/registration
端点发送POST
请求来注册自身。此端点的名称通常会在配置文件和文档中提供。
在请求正文中,客户端应用程序以 JSON 格式提交关于其自身的关键信息。例如,这通常包含一个重定向 URI 的白名单数组。它还可以提交一系列附加信息,例如要公开的端点名称、应用程序名称等。典型的注册请求可能如下所示:
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",
…
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
OpenID 提供商应要求客户端应用程序对自身进行身份验证。在上面的例子中,他们使用的是 HTTP Bearer 令牌。但是,某些提供商在允许动态客户端注册时,不进行任何身份验证,这使得攻击者能够注册自己的恶意客户端应用程序。这可能会产生各种后果,具体取决于 提供商 如何处理这些攻击者可控的属性值。
例如,你可能已经注意到,其中一些属性可以作为 URI 提供。如果 OpenID 提供商访问了其中任何一个,则可能会导致二阶 SSRF (opens new window) 漏洞,除非采取了额外的安全措施。
- name: 实验室-从业者
desc: 通过OpenID动态客户端注册来实现SSRF >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/oauth/openid/lab-oauth-ssrf-via-openid-dynamic-client-registration
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 5.2允许引用授权请求
到目前为止,我们已经了解了 提交授权请求所需参数 的标准方式,即通过查询字符串来提交。某些 OpenID 提供商提供了一种选项,可以将这些令牌作为 “JSON web token”(JWT)来传递。如果支持此功能,则可以发送单个request_uri
参数,指向其余 OAuth 参数及其对应的 JSON web 令牌。根据 OAuth 服务的配置,此request_uri
参数是 SSRF 的另一个潜在向量。
(译者加:注意,“request_uri” 和 “redirect_uri” 是两个不同的参数)
你还可以使用此功能绕过 对这些参数值的验证。某些服务器可以有效地验证授权请求中的查询字符串,但可能无法对 JWT 中的参数(包括redirect_uri
)充分应用相同的验证。
要检查目标是否支持此选项,你应该在配置文件和文档中查找request_uri_parameter_supported
选项。或者,你可以尝试添加request_uri
参数以测试它是否有效。有时你会发现,某些服务器虽然在文档中没有明确提及,但其还是支持此功能。