什么是PKCE?

在Connect App的设置页面,如果勾选了Enable OAuth Settings,就会出现很多让人眼花缭乱的选项。

其中,名字最长的一项叫做 Require Proof Key for Code Exchange (PKCE) Extension for Supported Authorization Flows.

简称PKCE

那么什么是PCKE呢?

先用一个不恰当的比喻来看Oauth2.0流程

张三要去工厂视察,向办公室主任出示了自己的账号和密码身份证和员工号(Credential),
办公室主任验明身份后(原来是你老小子)给张三开具了签字盖章的介绍信(code),并且通知门岗张三计划到访。门岗没有身份核实的能力(是七十岁老大爷),但可以识别介绍信的真伪,所以只看信不看人。
如果介绍信没问题(code redeem),给张三发放通行证(access token),凭通行证可以进入工厂。工厂门禁只看通行证不看人。

看起来这一切天衣无缝,兄弟们,安全又卫生。

但是,某天M国商业间谍打算去工厂盗取机密技术,他了解了访问流程后,制定了如下计划。

M国商业间谍Lee Si了解到工厂门岗只看介绍信不认人,他就埋伏在张三身边,计划趁机(通信嗅探)打晕了张三抢走介绍信(code)。然后自称是张三(门岗大爷:咋看着还是个混血呢),使用介绍信换取(redeem)通行证(access token)就可以顺利进入工厂。

可是,在Lee Si动手的前一天,工厂升级了访问流程,现在变成了这样。

新的访问流程,要求验证身份拿介绍信的时候,从几十亿颗核桃里随便挑一颗核桃(code verifier),然后用核桃纹路盖章(Signature),并同身份证明信息一同上交(code challenge)。
随后,拿着介绍信换取通行证时,需要将这颗核桃交给门岗进行纹路比对,当证明信有效且提供的核桃纹路能对上开始提供的核桃纹路才可以换取通行证。

这次,Lee Si打晕张三只能获得证明信,却不知道张三到底用的是哪颗核桃的纹路(为了能尽可能的比喻其安全机制,假设张三随身带了三十万颗核桃,只有他自己知道用的是哪颗),只有一次验证的机会,如果核桃纹路对不上就会被当场抓起来。

这就是PKCE的意义。

总结一下,
原流程:
1. 使用认证信息,通过认证服务器获取Code
2. 使用code换取Access Token访问资源服务

PKCE加持后流程:
1. 本地生成随机字符串作为code verifier,使用哈希算法对Code Verrifier进行签名,生成Code Challenge。
2. Code Callenge,使用的签名算法与认证信息一共提交认证服务器获取Code。
3. 将Code与Code Verifier,注意是,Code Verifier同时发送服务器换取Access Token。
4. 服务器使用Code Verifier与步骤一声明的哈希签名算法生成签名并与Code Challenge作比较,如果一致且code有效则返回Access Token。

这里的奥秘在于,网络嗅探只能获取http请求的目标以及参数。虽然可以截获code challenge,哈希算法与Code,但是因为Code Verifier在code兑换之前从来没有发送过,只存在本地且每次随机生成,所以通过嗅探无法被截获,并且因为哈希算法的非对称计算特性,不使用只有未来的才存在的量子计算机,无法很快的通过Code Challenge反算出有效的Code Verifier(如果你能做到,就相当于拆掉了现在信息世界的安全地基,请务必先告诉我,咱俩一起拿诺贝尔奖分奖金)。

如果没有PKCE,仅通过Code就可以获得Access Token,但有了PKCE,就可以保证来换取的Access Token的人(客户端)就是当初通过身份验证的人(客户端),从而防止通过网络嗅探而进行的身份伪冒。

这里需要明确指出的是,PKCE只能保护Code不被冒用,但并不负责Credential泄露与Access Token泄露,所以本质上PKCE只是在不可信任客户端与不可信任环境下的安全拓展(比如,无法安全的储存Client Secret,公开的App Package,不确定的运行环境,不确定的网络环境)。如果有类似的安全隐患一定要开,信息安全就是木桶原理,只要有一块短板则功亏一篑,切记!