我正在构建两个应用程序:前端和后端。
后端将使用Rails API + Doorkeeper (oauth2提供程序)构建,而前端将使用React构建。
目前,我正在使用“客户凭据授权流”,该流程目前运行良好。但是经过一段时间的研究后,这个流程不应该被应用程序使用,因为如果有人对应用程序进行解压缩,它就会公开client_secret
。
我还读过“隐式格兰特流”,它只需要client_id
。但现在这股潮流似乎已经过时了?
根据这个:https://auth0.com/docs/api-auth/which-oauth-flow-to-use#is-the-client-a-single-page-app-
它建议在“隐式授权流”上使用“带有PKCE的授权代码授予”。我可以让它工作,但问题是,它仍然需要client_secret
才能得到一个access_token
,这应该是什么样子?
下面是我正在做的示例流:
curl -X POST 'http://localhost:3000/oauth/authorize?client_id=xxxx&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=public&code_challenge=testchallenge&code_challenge_method=plain'
这将给我以下答复:
{
"status": "redirect",
"redirect_uri": {
"action": "show",
"code": "8quZ-EAiKKG2EKnQiSYs3xeFRCgsIwcTbaWNdjnpyFg"
}
}
然后,我将使用上面的代码来使用下面的请求获取访问令牌:
curl -i http://localhost:3000/oauth/token \
-F grant_type="authorization_code" \
-F client_id="xxxx" \
-F client_secret="xxxx" \
-F code="8quZ-EAiKKG2EKnQiSYs3xeFRCgsIwcTbaWNdjnpyFg" \
-F redirect_uri="urn:ietf:wg:oauth:2.0:oob" \
-F code_verifier="testchallenge"
现在是问题所在,为了将code
转换为access_token
,我仍然需要client_secret
。如果两者只公开我的client_secret
,这与“客户凭据授予流”有什么区别?
上述命令将返回以下命令:
{
"access_token": "nQoorBqLxQH4qFpmlx3mGG6Cd_TfX4d3L3gAGOTwrFs",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "public",
"created_at": 1595517643
}
如果我没有在请求中包含client_secret
,下面是响应:
{
"error": "invalid_client",
"error_description": "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method."
}
以下是我的问题:
client_secret
来获得PKCE流上的access_token
吗?client_secret
,为什么建议使用"PKCE流“?client_secret
的“客户凭据授予流”有何不同?门卫PKCE文档:https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-PKCE-flow
发布于 2020-07-23 09:12:09
那得看情况。最初,PKCE是为了保护公共客户端(不能保护秘密的客户端)而引入的。但是最近,在实践中,PKCE成为了授权代码授予(来源)的推荐。
2.1.1.授权代码授予 客户必须防止将授权代码注入(重放)到 攻击者的授权响应。PKCE RFC7636的使用 为此目的而推荐。也可以使用OpenID连接"nonce“参数和ID令牌声明OpenID。PKCE的挑战 OpenID连接“当前”必须是事务特定的,并且必须是安全的。 绑定到事务所在的客户端和用户代理。 开始了。 注意:尽管到目前为止,PKCE是作为保护 本机应用程序,此建议适用于所有类型的OAuth客户端, 包括网络应用。
总之,为了避免授权代码重播攻击(规格-游戏攻略)。这种情况发生在终端用户的设备中,而不是在数据传输中。对于TLS 2.0令牌请求,TLS是必需的。
任何授权都不会公开凭据,因为令牌请求是通过TLS完成的。
我认为在您的情况下,客户端是一个机密客户端(规范-客户端类型)。因此,我建议在授权服务器中检查这个方面。
发布于 2020-07-27 14:43:22
更新
与此同时,建议发生了变化(也见Kavindu的答复,以供参考),我希望确保这一点在这个答复中也得到强调。将PKCE作为补充客户端秘密的额外安全层,对于机密客户端也是有意义的。客户端秘密允许授权服务器(标识提供程序)确定客户端的身份。
使用PKCE可以确保试图将授权代码交换给令牌的一方首先是实际请求授权代码的方。因此,为了避免拦截场景,在顶部添加PKCE也是有意义的,即使是对机密客户端也是如此。
但是请记住,并不是所有的身份提供者都可能同时支持使用PKCE和客户端机密。
至于向守门人提出的问题,这种行为在此期间也可能发生变化。
原始答案
使用PKCE的授权代码流是为客户端无法安全地保护秘密的设置而发明的。因此,当您在PKCE中使用授权代码流时,不需要一个秘密,或者更准确地说,客户端秘密没有任何意义。
您所体验的似乎是一个Doorkeeper (参见https://github.com/doorkeeper-gem/doorkeeper/issues/1089)。所以我担心在他们修好之前你得用一些假的客户秘密。
但是,只要正确地实现了PKCE流的其余部分,这就不应该是一个问题,因为这个流不依赖于任何静态客户端秘密,而是使用您已经指出的动态创建的代码验证器。
我不确定我是否正确地理解了您所使用的处理登录的客户端类型。如果是SPA或移动应用程序,您应该在PKCE中使用授权代码流,但是如果您正在实现一个“经典”web应用程序,在某些后端服务中对登录进行处理,则应该使用使用客户端秘密的正常授权代码流,因为可以信任后端来保护机密。
顺便说一句,我刚刚在我的一个项目中检查了代码,我在其中构建了一些通过Auth0作为身份提供者进行身份验证的角SPA。我在那里使用PKCE的授权代码流,而且我肯定不会向Auth0发送任何静态客户端秘密(就像原始授权代码流中的那样),因为显然该流程是按预期实现的。所以这一定是门卫的问题。
另一件事:我不知道您提供的请求是否只是示例,但与其使用简单的方法将代码验证器转换为代码挑战,我更愿意使用安全的方法,如S256,而不是您在问题中引用的RFC中的建议。
发布于 2020-07-24 01:36:05
我在Rails控制台中创建了这样一个Doorkeeper::Application
:
Doorkeeper::Application.create :name => 'Test App', :uid => 'xxxx', :secret => 'xxxx', :redirect_uri => 'urn:ietf:wg:oauth:2.0:oob'
似乎我需要将Doorkeeper::Application
的机密字段设置为false
,这样才能获得没有client_secret
的access_token
。
因此,上述代码将成为:
Doorkeeper::Application.create :name => 'Test App', :uid => 'xxxx', :secret => 'xxxx', :redirect_uri => 'urn:ietf:wg:oauth:2.0:oob', :confidential => false
我在以下网站找到了解决方案:spec.rb#L348
https://stackoverflow.com/questions/63057801
复制相似问题