测试 OAuth 弱点
ID |
---|
WSTG-ATHZ-05 |
总结
OAuth2.0 (hereinafter referred to as OAuth) (以下简称 OAuth)是一个授权框架,允许客户端代表其用户访问资源。
为了实现这一点,OAuth 严重依赖令牌在不同实体之间进行通信,每个实体都有不同的角色:
-
资源所有者:授予对资源的访问权限的实体、所有者,在大多数情况下是用户自己
-
客户:代表 Resource Owner 请求访问资源的应用程序。这些客户端有两种类型:
- Public:无法保护密钥的客户端(例如,专注于前端的应用程序,如 SPA、移动应用程序等)
- 机密:能够通过保护其注册密钥的安全来安全地向授权服务器进行身份验证的客户端(例如后端服务)
-
授权服务器:保存授权信息并授予访问权限的服务器
-
资源服务器:提供客户端访问的内容的应用程序
-
资源所有者: 授予对资源的访问权限的实体、所有者,在大多数情况下是用户自己
-
客户: 代表 Resource Owner 请求访问资源的应用程序。这些客户端有两种类型:
- Public: 无法保护密钥的客户端(例如,专注于前端的应用程序,如 SPA、移动应用程序等)
- Confidential: 能够通过保护其注册密钥的安全来安全地向授权服务器进行身份验证的客户端(例如后端服务)
-
授权服务器: 保存授权信息并授予访问权限的服务器
-
资源服务器: 提供客户端访问的内容的应用程序
由于 OAuth 的责任是将所有者的访问权限委托给客户端,因此这对攻击者来说是一个非常有吸引力的目标,而不良的实施会导致对用户资源和信息进行未经授权的访问。
为了提供对客户端应用程序的访问权限,OAuth 依赖于多种授权类型 来生成访问令牌:
- 授权码:机密客户端和公共客户端都使用,以将授权码交换为访问令牌,但仅建议用于机密客户端
- 代码交换证明密钥 (PKCE):PKCE 建立在授权码授予之上,为公共客户端使用提供更强的安全性,并改善机密客户端的状况
- 客户端凭证:用于机器到机器的通信,其中这里的“用户”是请求从 Resource Server 访问其自身资源的计算机
- 设备代码:用于输入功能受限的设备。
- Refresh Token:授权服务器提供的 Token,允许客户端在用户的 Access Token 失效或过期时刷新 Token。此授权类型与另一种授权类型结合使用。
OAuth2.1 版本中将弃用两个流,不建议使用它们:
- 隐式流*:PKCE 的安全实施使此流过时。在 PKCE 之前,隐式流由客户端应用程序(如single page applications)使用,因为 CORS 放宽了站点相互通信的 same-origin policy 。有关为什么不建议使用隐式授权的更多信息,请查看 此部分section.
- 资源所有者密码凭证:用于直接与客户端交换用户的凭证,然后客户端将用户凭证发送给授权机构以交换访问令牌。有关为什么不推荐此流程的信息,请查看 此部分section.
*:仅 OAuth 中的隐式流已弃用,但在 Open ID Connect (OIDC) 中仍是检索id_tokens
.请仔细了解隐式流的使用情况,如果仅使用 /authorization
endpoint 来获取访问令牌,而不以任何方式依赖 /token
endpoint,则可以识别隐式流。可以在此处here.找到这方面的示例。
请注意,OAuth 流程是一个复杂的主题,以上仅包括关键领域的摘要。内联引用包含有关特定流的更多信息
测试目标
- 确定 OAuth2 实现是易受攻击,还是使用已弃用的或自定义的实现。
How to Test
测试已弃用的授权类型
出于安全性和功能原因,已弃用的授权类型已过时。确定它们是否被使用使我们能够快速查看它们是否容易受到与其使用相关的任何威胁。有些可能超出攻击者的范围,例如客户端使用用户凭证的方式。这应该记录下来并提交给内部工程团队。
对于公共客户端,通常可以在对终端节点的请求中识别 /token
授权类型。它在令牌交换中用参数grant_type
表示。
以下示例显示了使用 PKCE 的授权码授予。
POST /oauth/token HTTP/1.1
Host: as.example.com
[...]
{
"client_id":"example-client",
"code_verifier":"example",
"grant_type":"authorization_code",
"code":"example",
"redirect_uri":"http://client.example.com"
}
grant_type
参数的值及其指示的授权类型为:
password
:表示 ROPC 授权。client_credentials
: 表示客户端凭证授予。authorization_code
: 表示授权码授予。
隐式流类型不由grant_type
参数指示,因为令牌显示在对终端节点/authorization
请求的响应中,而是可以通过response_type
.下面是一个示例。
GET /authorize
?client_id=<some_client_id>
&response_type=token
&redirect_uri=https%3A%2F%2Fclient.example.com%2F
&scope=openid%20profile%20email
&state=<random_state>
以下 URL 参数指示正在使用的 OAuth 流:
response_type=token
:表示 Implicit Flow,因为客户端直接从授权服务器请求返回令牌。response_type=code
:指示授权代码流,因为客户端正在向授权服务器请求返回一个代码,该代码将在之后与令牌交换。code_challenge=sha256(xyz)
:指示 PKCE 扩展,因为没有其他流使用此参数。
以下是使用 PKCE 的授权代码流的授权请求示例:
GET /authorize
?redirect_uri=https%3A%2F%2Fclient.example.com%2F
&client_id=<some_client_id>
&scope=openid%20profile%20email
&response_type=code
&response_mode=query
&state=<random_state>
&nonce=<random_nonce>
&code_challenge=<random_code_challenge>
&code_challenge_method=S256 HTTP/1.1
Host: as.example.com
[...]
公共客户端
建议对公共客户端使用带有 PKCE 扩展的授权代码授予。使用 PKCE 的授权代码流的授权请求应包含 response_type=code
和code_challenge=sha256(xyz)
. 。
令牌交换应包含 grant type authorization_code
and a code_verifier
.
公共客户端的不当授权类型包括:
- 不使用 PKCE 扩展的授权码授予
- 客户端凭证
- 隐式流
- ROPC
机密客户端
建议对机密客户端使用授权码授予。也可以使用 PKCE 扩展。
机密客户端的不当授权类型包括:
- 客户端凭证(机器到机器除外 – 见下文)
- 隐式流
- ROPC
机器对机器
在没有发生用户交互且客户端只是机密客户端的情况下,可以使用客户端凭据授予。
如果您知道 client_id
and client_secret
,则可以通过传递client_credentials
grant 类型来获取令牌。
$ curl --request POST \
--url https://as.example.com/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"<some_client_id>","client_secret":"<some_client_secret>","grant_type":"client_credentials"}' --proxy http://localhost:8080/ -k
凭证泄漏
根据流程,OAuth 将多种类型的凭证作为 URL 参数传输。
以下令牌可被视为凭据泄露:
- 访问令牌
- 刷新令牌
- 授权码
- PKCE 代码质询 / 代码验证器
由于 OAuth 的工作方式,授权code
以及code_challenge
、 和 code_verifier
可能是 URL 的一部分。如果 response_mode
未设置为 form_post
,则隐式流会将授权令牌作为 URL 的一部分进行传输。这可能会导致反向链接标头、日志文件和代理中请求的令牌或代码泄漏,因为这些参数是在查询或片段中传递的。
泄漏令牌的隐式流所带来的风险远高于泄漏 code
或任何其他code_*
参数,因为它们与特定客户端绑定,并且在泄漏的情况下更难被滥用。
为了测试此方案,请使用 HTTP 拦截代理(如 ZAP)并拦截 OAuth 流量。
- 逐步完成授权过程并识别 URL 中存在的任何凭证。
- 如果 OAuth 流涉及的页面中包含任何外部资源,请分析向这些资源发出的请求。凭证可能会泄露给反向链接标头。
在逐步完成 OAuth 流并使用应用程序后,将在 HTTP 拦截代理的请求历史记录中捕获一些请求。在请求历史记录中搜索包含授权服务器和客户端 URL 的 HTTP 反向链接标头(例如 Referer: https://idp.example.com/
)。
查看 HTML 元标记(尽管并非所有浏览器都支持此标记)或 Referrer-Policy 可以帮助评估是否通过反向链接标头发生任何凭据泄漏。
相关测试用例
修复
- 实施 OAuth 时,请始终考虑所使用的技术,以及应用程序是可以避免泄露机密的服务器端应用程序,还是不能避免泄露机密的客户端应用程序。
- 几乎在任何情况下,都可以将授权码流与 PKCE 一起使用。一个例外可能是机器到机器流。
- 使用 POST 参数或标头值传输密钥。
- 当不存在其他可能性时(例如,在无法迁移的旧版应用程序中),请实现其他安全标头,例如
Referrer-Policy
.