模式|OAuth 2.0 扩展协议之 PKCE( 四 )


publicstaticstringbase64urlencodeNoPadding( byte[] buffer ) {stringbase64 = Convert.ToBase64String(buffer); base64 = base64.Replace( "+" ,"-"); base64 = base64.Replace( "/" ,"_"); base64 = base64.Replace( "=" ,""); returnbase64; }stringcode_challenge = base64urlencodeNoPadding(sha256(code_verifier));
原理分析
上面我们说了授权码拦截攻击 , 它是指在整个授权流程中 , 只需要拦截到从授权服务器回调给客户端的授权码code , 就可以去授权服务器申请令牌了 , 因为客户端是公开的 , 就算有密钥client_secret也是形同虚设 , 恶意程序拿到访问令牌后 , 就可以光明正大的请求资源服务器了 。
PKCE是怎么做的呢? 既然固定的client_secret是不安全的 , 那就每次请求生成一个随机的密钥(code_verifier) , 第一次请求到授权服务器的authorize endpoint时 ,携带code_challenge 和 code_challenge_method , 也就是code_verifier转换后的值和转换方法 , 然后授权服务器需要把这两个参数缓存起来 , 第二次请求到token endpoint时 , 携带生成的随机密钥的原始值 (code_verifier), 然后授权服务器使用下面的方法进行验证:
  • plain
code_challenge = code_verifier
  • S256 code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
通过后才颁发令牌 , 那向授权服务器authorize endpoint和token endpoint发起的这两次请求 , 该如何关联起来呢? 通过授权码code即可 , 所以就算恶意程序拦截到了授权码code , 但是没有code_verifier , 也是不能获取访问令牌的 , 当然PKCE也可以用在机密(confidential)的客户端 , 那就是client_secret + code_verifier双重密钥了 。
最后看一下请求参数的示例:
GET /oauth2/authorize https://www.authorization-server.com/oauth2/authorize?response_type=code&client_id=s6BhdRkqt3&scope=user&state=8b815ab1d177f5c8e &redirect_uri=https://www.client.com/callback&code_challenge_method=S256 &code_challenge=FWOeBX6Qw_krhUE2M0lOIH3jcxaZzfs5J4jtai5hOX4
POST /oauth2/token Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedhttps://www.authorization-server.com/oauth2/token?grant_type=authorization_code&code=d8c2afe6ecca004eb4bd7024&redirect_uri=https://www.client.com/callback&code_verifier=2D9RWc5iTdtejle7GTMzQ9Mg15InNmqk3GZL-Hg5Iz0
下边使用Postman演示了使用PKCE模式的授权过程 。

模式|OAuth 2.0 扩展协议之 PKCE
文章图片

参考文献