OAuth 2.0 中的 State 参数作用解析
State 参数:防御 CSRF 攻击
State 参数在 OAuth 2.0 框架中用于防止 ++CSRF++(跨站请求伪造)攻击。
CSRF 攻击指攻击者诱导用户在已登录的 Web 应用上执行未授权操作。在 OAuth 的场景下,CSRF 攻击可能导致敏感资源被非法获取,攻击者可通过劫持 OAuth 流程实现未授权访问。
State 参数通过维护授权流程的完整性,有效降低此类风险。
State 参数机制与验证流程
- State 参数是客户端应用在授权请求中附带的任意字符串。
- 授权服务器在重定向用户回客户端时,会一同返回 state 参数。
- 客户端收到响应后,需验证返回的 state 参数是否与最初发送的参数一致。
- 只有验证通过,才能确保此次响应是合法的 OAuth 流程延续,而非 ++CSRF++ 攻击造成的。
State 参数弱或缺失的风险
- 若 state 参数缺失 或易预测 (如使用静态值 "state" 或简单的序号),攻击者可利用漏洞发起 OAuth 流程,指定恶意重定向 ++URI++。
- 用户完成认证与授权后,授权服务器会将授权码重定向到攻击者控制的 ++URI++,造成安全隐患。
实操场景举例
以下为攻击者视角的演示,仅供安全学习使用。
- 使用链接 http://mycontacts.thm:8080/csrf/index.php 以及凭据 attacker:attacker 登录网站。

- 登录后,你会看到一个页面,该页面允许你将联系人同步到 CoffeeShopApp 账户。

- 点击"Sync Contacts"后,会跳回到同步页面。

URL 分析与授权流程
原始 URL
html
http://coffee.thm:8000/accounts/login/?next=/o/authorize/%3Fresponse_type%3Dcode%26client_id%3Dkwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN%26redirect_uri%3Dhttp%253A%252F%252Fmycontacts.thm%253A8080%252Fcsrf%252Fcallbackcsrf.php
解析流程
- 第一层登录地址:
http://coffee.thm:8000/accounts/login/
进入 Coffee 登录页面。 - 参数说明
?next=...
登录成功后自动跳转到 next 参数指定的地址。 - next 参数解码后
/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http%3A%2F%2Fmycontacts.thm:8080%2Fcsrf%2Fcallbackcsrf.php - redirect_uri 再次解码后
http://mycontacts.thm:8080/csrf/callbackcsrf.php
完整授权流程
- 打开 Coffee 登录页
- 用户登录 Coffee
- 登录成功后,进入 /o/authorize/
- Coffee 生成 authorization code
- Coffee 把 code 发送到 mycontacts 的 callbackcsrf.php
关键参数说明
- response_type=code:请求授权码
- client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN:申请授权的客户端应用(ContactApp / mycontacts)
- redirect_uri=http://mycontacts.thm:8080/csrf/callbackcsrf.php:授权完成后回调地址
安全隐患分析
本题安全问题并不在于 redirect_uri 被篡改,而是:
缺少 state 参数
正常 OAuth 授权请求应包含:
state=随机值
如:
/o/authorize/?response_type=code&client_id=...&redirect_uri=...&state=abc123random
但该 URL 缺少:
state=
风险:
- 客户端无法判断 callback 是否为自己发起的授权流程。
攻击流程举例
- 攻击者先获取自己的 code
- 诱导 victim 访问:
http://mycontacts.thm:8080/csrf/callbackcsrf.php?code=攻击者的code - victim 的 mycontacts 会误以为这是自己授权回来的 code
- 结果是 victim 的 mycontacts 账号绑定了攻击者的 Coffee 账号
一旦账户同步完成,所有联系人信息都会转移到攻击者账户。
授权码获取与拦截
- 攻击者可通过 Burp Suite 等工具拦截授权过程,获得授权码。
我们提供了一个授权链接:
http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http://coffee.thm:8000/oauthdemo/callbackforcsrf/
通过该链接可直接获得授权码,无需完成完整 OAuth 流程。
示例代码
python
def oauth_logincsrf(request):
app = Application.objects.get(name="ContactApp")
redirect_uri = request.POST.get("redirect_uri", "http://coffee.thm/csrf/callbackcsrf.php") authorization_url = (
f"http://coffee.thm:8000/o/authorize/?client_id={app.client_id}&response_type=code&redirect_uri={redirect_uri}" )
return redirect(authorization_url)
bash
def oauth_callbackflagcsrf(request):
code = request.GET.get("code")
if not code:
return JsonResponse({'error': 'missing_code', 'details': 'Missing code parameter.'}, status=400) if code:
return JsonResponse({'code': code, 'Payload': 'http://coffee.thm/csrf/callbackcsrf.php?code='+code}, status=400)
- 访问上述链接,使用凭据 attacker:tesla@123 获得授权码。
- 响应中的 URL 参数(Payload)即为攻击用数据,请复制其值用于后续攻击。

发起攻击流程 Launching the Attack
- 攻击者获得授权码后,准备 CSRF 载荷。例如,向受害者发送如下链接:
- http://bistro.thm:8080/csrf/callbackcsrf.php?code=xxxx(xxxx 为攻击者授权码)
- 受害者点击链接后,攻击者的 CoffeeShopApp OAuth 账户会与受害者账户关联,受害者的联系人信息被转移到攻击者账户。

照此操作即可拿到 flag。

为什么直接拿到 flag?
你可能会疑惑,为什么如此容易就获得 flag?下面详细解析:
身份与系统划分:
- 身份:
- attacker:攻击者
- victim:受害者
- 系统:
- coffee.thm:OAuth 授权服务器
- mycontacts.thm:联系人同步应用
正常功能流程
- mycontacts 网站功能:同步 CoffeeShopApp 联系人到 mycontacts
- 正常流程:
- victim 登录 mycontacts
- victim 点击 Sync Contacts
- victim 跳转至 coffee.thm 登录/授权
- coffee 返回 victim 的 code
- mycontacts 用 code 换 token
- mycontacts 同步 victim 的联系人
攻击流程
- 攻击者目标:让 victim 的 mycontacts 账号绑定/同步 attacker 的 Coffee 账号
- 步骤:
- 攻击者用自己的 Coffee 账号获取 code(attacker_code)
- 构造链接:
http://mycontacts.thm:8080/csrf/callbackcsrf.php?code=attacker_code - 诱导 victim 在已登录 mycontacts 状态下访问该链接
攻击为何成功
- 因为 OAuth 请求缺少 state 参数
- state 的作用:让 mycontacts 记住回调是否为当前用户自己发起的
- 没有 state,mycontacts 无法判断 code 来源,误以为是 victim 自己授权回来的 code
- 用该 code 换 token,实际获得的是 attacker 的 Coffee token
- 最终,victim 的 mycontacts 账号与 attacker 的 Coffee 账号关联
为什么"一下就拿到 flag"
- 靶场用 flag 直接表示最终影响
- 一旦 victim 执行带 attacker_code 的链接,系统判定 CSRF 成功,返回 flag
现实中的影响可能包括: - 受害者账号被绑定到攻击者第三方账号
- 攻击者可通过 OAuth 登录受害者账户
- 受害者数据被同步到攻击者账户
- 账户关联关系被篡改