OAuth 授权码用码换令牌
授权码流程把访问令牌的交付移到令牌端点,而不是在面向浏览器的授权重定向里直接返回访问令牌。这能减少令牌暴露在地址中的机会,却不代表浏览器绝不可能持有令牌。究竟由谁兑换授权码,以及结果保存在哪里,取决于客户端架构。审阅时应区分协议步骤、客户端类型和实际存储位置,不能把一种部署方式当成整个流程的定义。 授权跳转传递授权码,令牌端点交付令牌。PKCE、客户端与回调绑定、过期和单次使用各守一条边界。存储方式取决于客户端架构;离线模型不能证明完整登录流程。 公共客户端也能使用授权码流程 机密 Web 后端可以向令牌端点进行客户端认证,并把令牌保存在服务端。浏览器随后使用应用自己的会话,但会话安全仍需单独处理。原生应用和浏览器应用等公共客户端无法可靠地保守分发出去的客户端秘密,然而它们仍然可以使用授权码加 PKCE。因此,授权码流程并不是只有后端才能采用的方案。 若浏览器应用自行兑换,JavaScript 就会收到令牌响应。流程避免了在授权跳转地址里交付访问令牌,却不会消除脚本被入侵或令牌存储泄露的问题。后端架构改变了边界,并没有让所有浏览器侧风险消失。OAuth 解决委托访问;需要确认用户身份的应用,应采用 OpenID Connect 等适合的身份协议,并验证其中独立的身份凭据,不能把任意访问令牌直接当作登录证明。 把兑换绑定到原始请求 PKCE 为每次事务生成高熵校验串。授权请求携带它的 S256 挑战,令牌请求再提供原校验串,授权服务器检查二者是否对应。校验串不是固定的客户端口令,必须与发起它的事务关联。这样,只有截获授权码、却没有校验串的一方,不应能够完成兑换。日志和错误报告也不应同时泄露这两部分。 RFC 9700 要求公共客户端使用 PKCE,并建议机密客户端也使用。应选择 S256,避免降级成 plain。机密客户端仍需执行已配置的客户端认证,PKCE 不能代替这一职责。客户端认证也不一定意味着发送共享秘密;部署可以采用非对称认证机制。判断安全性时,要核对服务端实际执行的验证,而不是只看请求里出现了几个参数。 每枚授权码都应绑定客户端与回调地址,设置短有效期并限制只能使用一次。登记的回调地址通常必须精确匹配;原生应用的回环地址端口存在标准规定的例外。授权请求携带 redirect_uri 时,令牌请求中的值必须一致。在授权阶段就要拒绝未登记的回调,而不是等到授权码已泄露之后才靠兑换失败补救。 坏掉的样子 一次性并不能阻止攻击者抢先兑换一枚没有充分保护的授权码。过期只是缩短机会,不会让截获变得无害。回调中的授权码仍可能出现在访问日志、浏览器历史、来源信息和崩溃报告里。避免记录这些值,使用合适的 HTTPS 回调;开发原生客户端时,则按照原生回环重定向的专门规则处理,不要把例外扩展到任意明文回调。 ...