OAuth 框架定义了多种授权模式以满足不同的应用场景,例如:
授权码模式(Authorization Code Flow)
隐式授权模式(Implicit Flow)【现在接近废弃】
密码授权模式(Resource Owner Password Credentials Flow)
等等
PKCE(Proof Key for Code Exchange)是对现有授权码模式的加强,能够有效防御跨站请求伪造(CSRF)和授权码拦截攻击。
要清楚的一点是 PKCE 是可选的“强化包”:
如果客户端遵循 PKCE 协议与授权服务器通信,那么授权服务器会切换到加强的授权码模式,进而执行 PKCE 定义的额外验证;
如果客户端没有遵循 PKCE 协议,那么授权服务器会回退到基本的授权码模式。
目前,授权服务器兼容以上两种方式。但可以预想到在不久的将来,PKCE 可能变为强制执行,毕竟安全越来越重要。
PKCE 的三个核心要素
客户端(如 Web SinglePageApplication)生成一个由 43 至 128 个规定字符组成的随机字符串,称作 code_verifier。
客户端选择一种变换方法,称作“code_challenge_method”,用于稍后对 code_verifier 进行转换。目前,它只能为以下两者之一:
"plain",即 code_challenge = code_verifier
"S256",采用 SHA256 算法,即 code_challenge = base64(SHA256(code_verifier))。
使用选择的 “code_challenge_method” 对 code_verifier 进行变换得到的字符串,称作 code_challenge。
采用 PKCE 的授权码工作流
A) 客户端发授权请求 “/authorization” 到授权服务器,并附带上两个新的参数 “code_challenge” 和 “code_challenge_method”。
B) 授权服务器返回只能使用一次的授权码 “code”,同时必须记录 “code”、“code_challenge” 和 “code_challenge_method” 三者的关联关系。因为稍后要进行校验。授权服务器既可以将这些信息编码进 “code” 里,也可以直接存储在服务器端。
C) 客户端再次发获取令牌请求 “/token” 到授权服务器,并附带上 “code_verifier” 以及 “code”。
D) 授权服务器找到与该 “code” 关联的 “code_challenge” 和 “code_challenge_method”;使用保存的 “code_challenge_method” 对 客户端发过来的 “code_verifier” 进行变换,然后与 “code_challenge” 进行比较。若相同则可以正常授权,返回客户端请求的令牌。
PKCE 的优点
在不使用 PKCE 时,若授权码 code 被攻击者截持,那么攻击者就可以使用窃取的授权码 code 去获得一个合法的令牌 token,然后用 token 执行攻击行为。
在使用 PKCE 时,若授权码 code 被攻击者截持,那么攻击者也无法获得一个合法的令牌 token,因为攻击者还要提供 code_verifier,而 code_verifier 只有客户端才知道。