PKCE如何防范CSRF攻击?授权后恶意链接场景的防护原理
先明确:PKCE(Proof Key for Code Exchange)主要在OAuth 2.0授权码流程里防范CSRF,尤其针对无后端存储client_secret的公共客户端(比如SPA、移动APP)。
CSRF在授权码流程中的风险点
当你已登录授权服务器后,恶意网站可能构造一个授权请求链接(比如https://auth-server.com/authorize?client_id=xxx&redirect_uri=恶意地址&response_type=code)诱导你点击。此时授权服务器会误以为是你发起的合法请求,把授权码返回给恶意网站的回调地址。如果没有PKCE,攻击者拿到授权码就能兑换访问令牌——这就是CSRF的核心:冒用你的身份获取授权凭证。
PKCE通过code_verifier/code_challenge的防御逻辑
PKCE的核心是只有发起授权请求的合法客户端,才持有对应的code_verifier,才能完成授权码到令牌的兑换,具体步骤如下:
合法客户端的前置操作
你正常使用的客户端(比如某个SPA)会先生成一个随机的code_verifier(长随机字符串),再用SHA-256哈希(或指定算法)生成code_challenge,然后把code_challenge和哈希算法标识code_challenge_method(比如S256)一起加入授权请求,发送给授权服务器。授权服务器的关联存储
授权服务器收到请求后,会把code_challenge和当前用户会话、授权请求绑定存储,之后将授权码返回给客户端预先备案的合法回调地址。恶意链接的致命漏洞
当你点击恶意链接时,这个请求是攻击者构造的,它既没有生成对应的code_verifier,也没法提供合法的code_challenge——因为code_challenge是客户端本地随机生成的code_verifier的哈希值,攻击者无法提前预知。退一步说,就算攻击者硬编了一个
code_challenge,它也没有对应的code_verifier。当它拿到授权码(假设回调地址伪造成功)去兑换令牌时,必须提交code_verifier,授权服务器会用这个code_verifier重新计算哈希,和之前存储的code_challenge比对:- 合法客户端的
code_verifier计算出的哈希和code_challenge完全匹配,兑换成功; - 攻击者没有正确的
code_verifier,计算出的哈希必然和存储的code_challenge不匹配,兑换请求直接被拒绝。
- 合法客户端的
关于“访问/刷新令牌已发放”的情况
如果访问/刷新令牌已经合法发放,PKCE就不再起作用了——因为PKCE只负责授权码兑换令牌的环节,不涉及令牌的后续使用。后续的CSRF防范需要靠其他机制:比如把令牌存在HttpOnly、Secure属性的Cookie中,或者客户端在请求时携带CSRF令牌(比如XSRF-TOKEN),服务端验证请求中的令牌与Cookie中的是否一致。
内容的提问来源于stack exchange,提问作者user29988412

