OAuth PKCE
什么是 OAuth2 PKCE
OAuth PKCE(Proof Key for Code Exchange) 是 OAuth 2.0 的扩展,是为了验证 public client 而引入的,可以降低 public client 的安全风险。
已经有了授权码模式,为什么需要 PKCE
OAuth 授权涉及三方:用户、第三方 app(也就是 client)和 授权服务器。作为安全环节中的重要一环,OAuth 的一个重要特性便是验证 client。
当然我们这里不讨论隐式授权模式,这个模式是不推荐的,因为他不够安全。如果大家对该模式感兴趣可以去这里看看 What is the OAuth 2.0 Implicit Grant Type?
这里有个问题,有了授权码模式,需要 PKCE?
- 授权码(code)是用户授权,由授权服务器颁发给合法 client 的,而不是恶意 client。
- 为了防止 code 被盗用,因此在 code 换 token 的时候需要校验 client。但是有些 client 是 public client,不能安全的存储客户端密码,因此必须采用其他方法认证客户端,PKCE 正是这样一种方式。
授权码模式能够正常工作的一个前提是 client 必须能够安全的存储它事先注册到授权服务器的认证信息,这个信息通常是 app_id 和 app_secret。
在 code 换取 access_token 的时候,client 会提供 app_id 和 app_secret,授权服务器根据 client 提供的信息来验证 client 是否是合法,如果合法则颁发 access_token。
如果 code 换取 access_token 仅仅发生在服务端,那么可以认为是安全的,因为 app_id 和 app_secret 都存储在后端服务器上,压根不会泄露到浏览器中。
纯客户端应用,例如 app 便是 public client,这类应用根本无法安全存储密钥,只要反编译 app 就可以获取密钥。 为了验证 public client,必须要采取其他认证方式,这便是我们要讲的 PKCE。
PKCE 工作流程
授权码模式就不介绍了,如果不了解可以看阮一峰写的文章:理解OAuth 2.0
授权码模式的工作原理在 rfc7636#page-3,上图便是来自该文档。
- A. client 创建并保存一个名为 code_verifier 的密钥,然后将密钥经过转换生成 code_challenge,我们假设转换函数为 t,那么有
code_challenge=t(code_verifier)
; - B. 客户端请求授权,带上 code_challenge 和 t_m,授权端点像往常一样响应,但记录了 code_challenge 和 转换方法 t_m;
- C. 客户端拿到授权码后,使用 code 换取 access_token,并带上 code_verifier;
- D. 授权服务器对 code_verifier 进行校验,由于在 A 步骤中已经知道了转换方法 t_m,于是使用 t_m 和 code_verifier 执行转换,如果转换结果和在 A 步骤中收到的 code_challege 匹配,则认证成功。
在这种模式下,即便恶意 client 能够拿到 code,但是恶意 client 却没有 code_verifier,也就没法换取 access_token 了。
最后附上一个 pkce 的 js 库,有需要可以直接使用 pkce-challenge。如果对如何生成 code_verifier 和 code_challenge 感兴趣,这也是一个很好的参考。
温馨提示:反馈需要登录