PKCE 和 state 参数在 OAuth 流程中的防护差异

1 人参与

很多人把 OAuth 登录里的 state 和 PKCE 混为一谈,觉得都是"防攻击的随机字符串",加上一个就够了。其实这俩防的根本不是同一件事,少了哪个,漏洞的入口都不一样。

咱们先说 state。它的活儿是对付授权流程里的 CSRF,也就是防止有人把受害者的授权结果偷偷接到攻击者自己的会话上。做法很直白:发起授权请求时生成一个随机值,回调回来时服务端得核对这个值跟当前用户会话里存的一不一致。如果服务端压根不校验 state,攻击者就能构造一条恶意链接,把受害者的授权码绑到自己控制的会话里,完成账号绑定那类攻击。换句话说,state 守的是"这次回调到底是不是同一个人、同一个浏览器发起的"。

PKCE 管的则是另一头。它靠 code_verifier 和 code_challenge 这一对配对来验证,防的是授权码在半路被截走后被人直接拿去换令牌。重点在"截获"这个场景——哪怕流程本身没被 CSRF,授权码一旦在传输中泄露,没有 PKCE 的话攻击者捡到码就能换令牌,尤其对单页应用、移动端这类公开客户端杀伤力很大。所以 PKCE 守的是"拿着这个授权码来兑换的,是不是最初发起请求的那个客户端"。

两者的边界别搞错

一个盯会话,一个盯授权码本身,这就是差异的核心。state 缺失,典型后果是登录 CSRF 和账号固定;PKCE 缺失或者只支持 plain 这种明文方式,典型后果是授权码被拦截后令牌泄露。它们的利用条件和影响面都不重叠,补上一个并不能顶替另一个。

实际判断风险时还得看有没有兜底。比如就算 state 没校验,但授权码兑换时跟客户端会话强绑定了,风险等级也会往下降;反过来,PKCE 虽然强制了却还接受 plain,攻击者在更苛刻的条件下仍有机会。对普通用户来说不用记这些细节,知道这是两道各管一摊的锁就够了——评估一个登录流程安不安全,不能看它"有没有随机参数",而要看这两道锁是不是都真的锁上了。

参与讨论

1 条评论
  • 虚拟守望者

    一直以为state和PKCE是一回事,原来管的东西完全不同

    回复