PKCE:什么和为什么

2020-12-05 21:49:03

您会听到工程师之间的对话,并听到他们提到“ pixy”。不,他们不是在讨论仙女。他们指的是一种称为PKCE或代码交换证明密钥的新的,更安全的OAuth流。尽管此过程不涉及任何魔术,但PKCE确实为您的应用程序提供了一些巨大的安全优势,尤其是当您的应用程序在公共客户端上运行时。

PKCE提供动态的客户端机密,这意味着您的应用程序的客户端机密可以保持秘密(即使您的应用程序没有后端)。 PKCE比隐式流(也称为“令牌流”)更好,更安全。如果您使用隐式流程,则应切换到PKCE。如果您使用隐式流程来授权您的Dropbox应用程序,则PKCE是一种更好,更安全的替代方法,并且您不应再使用隐式流程。

在本文中,我们将探讨PKCE的工作原理,重要性,以及如何在今天的Dropbox应用中开始使用PKCE Flow。

PKCE是一种新的,更安全的授权流程(基于OAuth 2.0规范),最初是为了更好地保护移动应用程序而创建的,但是在所有OAuth客户端中都很有价值。

“ PKCE(RFC 7636)是对授权码流程的扩展,可以防止多种攻击并能够安全地从公共客户端执行OAuth交换。”

OAuth 2.0规范是用于授权的行业标准协议,并允许用户向应用授予访问其Dropbox数据的权限。使用OAuth 2.0,用户可以从第三方应用程序访问其Dropbox数据,而无需敏感信息(例如密码)。

有关Dropbox如何实现OAuth 2.0的更详尽的细分,请查看我们的OAuth指南。出于本文的目的,请使用下图了解一般授权流程。

Dropbox向应用程序发布访问令牌,该令牌可用于访问用户的Dropbox数据

最常见和最安全的OAuth流程是授权代码流程。不幸的是,该过程依赖于在最终访问令牌请求中提供client_secret的应用程序。对于某些类型的应用程序,这使泄漏秘密成为固有的,不可避免的风险,这就是为什么它们改而需要依赖隐式流程的原因。这些应用程序包括但不限于移动应用程序,JavaScript中的单页应用程序(SPA)和无服务器应用程序。

由于这些是公共客户,因此他们无法保证用于令牌交换的秘密的安全性。使用隐式流可以解决此问题,但存在在授权流末尾将访问令牌暴露在重定向URI中的风险,这使流容易受到不同类型的网络和恶意应用程序拦截的影响。

当应用无法发出跨域请求时,这种折衷是可以接受的(并且是必要的),这使得无法完成授权代码流。但是,由于CORS得到了广泛的支持,因此无需进行历史性的妥协。应用可以直接向令牌端点发出发布请求。

在没有跨域问题的情况下,公共客户端可以通过使用PKCE来利用授权代码流,该功能通过用动态生成的字符串替换静态客户端密钥来起作用。通过这样做,PKCE流消除了泄漏的机密,同时允许授权服务器验证请求访问令牌的应用与发起OAuth流的应用相同。

在授权码流的基础上,PKCE使用了三个新参数:code_verifier,code_challenge和code_challenge_method。我们先定义它们,然后再在整个流程中添加更多上下文。

code_verifier是您的应用程序生成的加密随机字符串。动态创建的字符串用于将最终访问令牌请求与初始授权请求相关联。换句话说,code_verifier是Dropbox授权服务器如何确保将访问令牌发布给请求授权的同一应用程序的方式。

code_challenge是使用以下两种可能的转换之一从code_verifier派生的:plain和S256。仅当无法使用S256时,才可以使用普通格式。对于大多数用例,code_challenge将是使用client_verifier进行的SHA256哈希的base 64编码。该字符串在服务器端被解密,用于验证请求是否来自同一客户端。

code_challenge_method告诉服务器使用了哪个函数来转换code_verifier(纯文本或S256)。如果保留为空,则默认为纯文本。

这些新参数用于补充授权代码流,以创建功能强大的检查系统,以使服务器可以验证授权请求和令牌请求均来自同一客户端。

当用户在您的应用中启动PKCE授权流程时,将发生以下情况:

客户端通过使用S256加密转换code_verifier来创建code_challenge。 (RFC 7636第4.2节)

客户端发送带有初始授权请求的code_challenge和code_challenge_method。 (RFC 7636第4.3节)

服务器使用来自初始授权请求的code_challenge_method转换code_verifier,并对照code_challenge检查结果。如果两个字符串的值都匹配,则服务器已验证请求来自同一客户端,并将发出access_token。 (RFC 7636第4.6节)

现在我们了解了流程,让我们看一下它的实际情况。

const base64Encode =(str)=> { 返回str.toString(' base64') .replace(/ \ + / g,'-') .replace(/ \ // g,' _') .replace(/ = / g,''); } const codeVerifier = base64Encode(crypto.randomBytes(32)); console.log(`客户端生成的code_verifier:$ {codeVerifier}`) const sha256 =(缓冲区)=> { 返回crypto.createHash(' sha256')。update(buffer).digest(); } const codeChallenge = base64Encode(sha256(codeVerifier)); console.log(`客户端生成的code_challenge:$ {codeChallenge}`)

注意:在生产中,授权代码通常发送到随授权请求一起传递的redirect_uri,但是此示例中省略了可选参数

服务器加密code_verifier并将其与code_challenge比较,以验证授权源和令牌请求是否匹配

{ " access_token&#34 ;:" NW7lYmEWHgUAAAAAAAAAAbeutI8iL5CuBik9_CPD5r83XvcQPt-7O5diOdUUcsuX&#34 ;, " expires_in&#34 ;: 14399, " token_type&#34 ;:"承载者&#34 ;, " uid&#34 ;:" 2589992144&#34 ;, " account_id&#34 ;:" dbid:AABuXdtqD88UpveXxu7rcVSo64ADcrWnBMk&#34 ;, " scope&#34 ;:" account_info.readcontacts.write file_requests.read file_requests.write files.content.read files.content.write files.metadata.read files.metadata.write" }

得益于巧妙的设计,一些字符串操作以及添加到您的请求中的几个额外参数,作为公共客户端(移动,SPA,无服务器等)的应用程序可以通过使用授权码流提供的增强的安全性。 PKCE。如果您的应用无法保证客户机密的安全性,那么您应该使用PKCE!

使用PKCE流是(另一个)使用已经内置PKCE的官方Dropbox SDK进行构建的重要理由。

由于更好的设计和整体安全性,我们强烈建议您用PKCE替换您的旧隐式流。 不确定哪个授权流程最适合您的需求? 请查看我们的OAuth指南以获取更多详细信息。 与往常一样,我们随时可以提供帮助! 您可以在我们的开发者论坛上发布您的问题或提交票证以获得更多直接支持。