PKCE
(RFC 7636) 是授权代码流的扩展,用于防止 CSRF 和授权代码注入攻击。
PKCE
不是客户端身份验证的一种形式,PKCE
不能替代客户端密码或其他客户端身份验证。即使客户端使用客户端密码或其他形式的客户端身份验证(如 private_key_jwt
),也建议使用 PKCE
。
注意:由于PKCE不能替代客户端身份验证,因此它不允许将公共客户端视为机密客户端。
PKCE
最初旨在保护移动应用程序中的授权代码流,但其防止授权代码注入的能力使其对每种类型的 OAuth
客户端都很有用,甚至是使用客户端身份验证的 Web
应用程序。
RFC 7636
:代码交换证明密钥(PKCE
,发音为“pixy”)是关于针对授权代码拦截攻击的对策的规范。
该规范于 2015 年 9 月发布。它添加了:
code_challenge
参数和 code_challenge_method
使用授权代码流的授权请求的参数。code_verifier
参数设置为与授权请求对应的令牌请求。此机制使授权服务器能够拒绝来自没有代码验证程序的恶意应用程序的令牌请求。
使用 PKCE
的授权请求会发出 parameter
,也可以选择 code_challenge_method parameter
发出 code_challenge
。
代码验证程序本身是使用 字符的随机字符串,最小长度为 43 个字符 [A-Z] / [a-z] / [0-9] / “-” / “.” / “_” / “~” ,最大长度为 128 个字符。
定义的代码质询方法是 plain 和 S256 。将代码验证器转换为代码质询的相应计算逻辑如下。
Method 方法 | Logic 逻辑 |
---|---|
plain | code_challenge = code_verifier |
S256 | code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))); code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) |
该 plain
方法不会更改输入,因此 的值 code_verifier
和结果 code_challenge
值相等。
该 S256
方法计算输入的 SHA-256
哈希值,然后使用 Base64-URL
对哈希值进行编码。例如,当 的值为 dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
时,该 code_challenge
值变 code_verifier
为 E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
。
当使用的代码质询方法是 S256
时,客户端应用程序必须通过在授权请求中包含 code_challenge_method=S256
参数来告知它。如果 code_challenge_method
省略参数,则授权服务器将假定 plain
为默认值。
生成授权代码后,授权服务器会将其保存到其数据库中,并在授权请求中包含代码质询和代码质询方法。
授权服务器稍后将使用保存的代码质询和代码质询方法来验证来自客户端应用程序的令牌请求。
来自授权终结点的响应对 PKCE
没有什么特殊之处。像往常一样,这是正常的反应。
从授权服务器接收授权代码后,客户端应用程序会发出令牌请求。除了授权代码之外,令牌请求还必须包含用于计算代码质询的代码验证程序。
用于指定代码验证程序的请求参数的名称为 code_verifier
。
支持 PKCE
的授权服务器的令牌终结点检查令牌请求是否包含有效的代码验证程序。
当然,仅当authorization_code grant_type
并且令牌请求中包含的授权代码与代码质询相关联时,才会执行此检查。
如果令牌请求不包含有效的代码验证程序,但满足上述条件,则该请求被视为来自恶意应用程序,授权服务器将返回错误响应。
通过比较两个代码质询来执行验证。
一个是授权请求中包含的内容,并存储在数据库中。另一个是授权服务器使用令牌请求中包含的代码验证程序和存储在数据库中的代码质询方法计算的内容。
如果两个代码质询相等,则令牌请求可被视为来自发出原始授权请求的合法客户端应用程序。否则,必须将令牌请求视为来自恶意应用程序。
如果验证了令牌请求,授权服务器将照常颁发访问令牌。