0xd00's blog

Back

一次由state参数缺失引发的OAuth 2.0 CSRF安全事件复盘Blur image

一次常规安全测试中的发现#

在一次对应用进行安全测试时,我注意到“绑定Google账户”功能的实现方式存在一个高风险隐患。

从表面看,授权流程非常标准:用户点击按钮,跳转至Google授权页面,同意后返回应用,完成绑定。但通过分析网络请求,我发现了一个关键问题:在向Google发起的授权请求URL中,缺少了 state 参数

在OAuth 2.0授权框架中,state 参数是防御跨站请求伪造(CSRF)攻击的核心机制。它的缺失,意味着授权流程存在被攻击者利用、导致账户接管的严重风险。

state 缺失如何导致账户接管#

缺少 state 参数的验证,为攻击者实施CSRF攻击提供了可能。攻击者可以诱导已登录用户,将其账户与攻击者控制的第三方账户进行绑定。

具体的攻击流程可以分解如下:

  1. 攻击者获取自身授权码:攻击者在自己的设备上发起“绑定Google账户”的流程,从跳转到Google的授权URL中,提取出包含自身Google账户信息的授权码(code)。
  2. 构造恶意请求:攻击者创建一个恶意页面或链接。当用户点击时,会向目标应用的回调接口发起请求,但请求中携带的是第一步中获取的、属于攻击者的授权码。
  3. 诱导受害者触发:攻击者通过社交工程等手段,诱导一个已登录目标应用的受害者访问该恶意链接。
  4. 完成恶意绑定:由于受害者在浏览器中保持着登录状态,目标应用的后端服务器在收到请求时,会误认为这是受害者本人发起的合法操作。服务器使用攻击者的授权码完成了绑定流程,结果是受害者的应用账户与攻击者的Google账户被绑定
  5. 实现账户接管:攻击者此后便可通过“使用Google登录”功能,直接访问受害者的账户。

整个过程的关键在于,服务器无法验证收到的回调请求是否源自最初由用户发起的、合法的授权流程。

修复过程中存在的误区#

我将此漏洞报告给开发团队后,团队迅速响应并推出了一个修复方案。然而,这个初版方案存在一个根本性的设计缺陷。

方案内容是:在前端通过JavaScript生成一个随机字符串作为 state,并将其存储在浏览器的 localStorage 中。当Google回调时,同样在前端通过JavaScript从 localStorage 中取出该值,与URL中的 state 参数进行比对。

这个方案是无效的,因为它违背了CSRF防御的一个核心原则:安全验证必须在可信的后端进行

客户端环境(包括 localStorage)对攻击者来说是完全透明且可控的。攻击者可以在他的恶意页面中轻易地生成任意 state 值,并将其同时置入 localStorage 和发往Google的请求中。对于只在前端进行验证的逻辑而言,这样的请求是“合法”的,因此漏洞并未得到实质性修复。

通过服务端生成与验证修复漏洞#

在指出前端验证方案的不足后,我们最终实施了行业标准的安全方案:将 state 参数的生成、存储和验证全部置于后端服务器管理。

正确的流程如下:

攻击流程图

  1. 服务端生成与存储 state:当用户发起绑定请求时,后端服务器生成一个高熵的、不可预测的随机字符串作为 state 值。同时,将此 state 值与当前用户的会话(Session)进行绑定,并设置一个较短的有效期。
  2. 向客户端下发 state:后端将生成的 state 值附加到提供给前端的Google授权URL中。
  3. Google回调:用户完成授权后,Google会将授权码 code 和原始的 state 参数一并发送至应用的回调接口。
  4. 服务端验证 state:在回调接口中,后端服务器从当前用户的会话中取出之前存储的 state 值,并与请求URL中的 state 参数进行严格、恒定时间的比较(timing-safe comparison)。
    • 如果两者完全匹配,则证明该请求是合法的,可以继续后续的授权流程。
    • 如果不匹配或会话中不存在对应的 state 值,则必须立即拒绝该请求,因为它极可能是一次CSRF攻击。

通过这个闭环流程,state 参数成为了一个一次性的、与用户会话强绑定的令牌,确保了授权请求的完整性和真实性,从而根除了CSRF攻击的威胁。

思考#

这次安全事件再次强调了几个基础但至关重要的安全开发原则:

  1. 严格遵循安全规范:OAuth 2.0等成熟框架中的每一个参数都有其明确的安全目的,不可随意省略或误用。
  2. 明确信任边界:安全相关的验证逻辑必须在服务端执行,绝不能依赖任何来自客户端的数据或逻辑。
  3. 理解安全机制的原理:只有深入理解了 state 参数为何能防范CSRF,才能设计出真正有效的安全方案,避免做出“看似修复”的无效改动。

希望本次复盘能为其他开发者在实施OAuth 2.0及类似授权协议时提供有价值的参考。

一次由state参数缺失引发的OAuth 2.0 CSRF安全事件复盘
https://blog.0xd00.com/blog/oauth-state-parameter-csrf-fix
Author 0xd00
Published at 2025年8月12日
Comment seems to stuck. Try to refresh?✨