我正在构建2个应用程序;前端和后端。
后端将使用Rails API + Doorkeeper Gem(oauth2提供程序)构建,而前端将使用React Native构建。
当前,我正在使用“客户端凭据授予流程”,目前该功能正常。但是经过一段时间的研究,不应将此流程用于仅用于客户端的应用程序,因为一旦有人反编译该应用程序,它就会公开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 Flow”?client_secret
)有何不同?Doorkeeper PKCE文档:https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-PKCE-flow
答案 0 :(得分:2)
使用PKCE的授权代码流,用于客户端无法安全保护机密的设置。因此,当将授权代码流与PKCE结合使用时,您不需要秘密,或者更确切地说,客户秘密将毫无意义。
您似乎遇到的是 Doorkeeper错误(请参阅https://github.com/doorkeeper-gem/doorkeeper/issues/1089)。因此,恐怕在他们修复该问题之前,您将不得不使用一些虚拟客户端机密。
但是,只要Doorkeeper正确地实现了其余PKCE流,这就不会成为问题,因为该流不依赖于任何静态客户端机密,而是使用您已经指出的动态创建的代码验证程序。
我不确定我是否正确理解您正在使用哪种客户端来处理登录。如果是SPA或移动应用程序,则应将授权代码流与PKCE一起使用,但是如果要实现“经典” Web应用程序,其中登录是在某些后端服务中处理的,则应使用普通的授权代码流,并使用客户端密码,例如可以信任后端来保护机密。
顺便说一句,我只是检查了我正在开发的一个项目Angular SPA中的代码,该项目通过Auth0作为身份提供者进行身份验证。我在那里使用带有PKCE的授权代码流,而且我绝对不会将任何客户端机密发送到Auth0,因此,这似乎确实是Doorkeeper的问题。
另一件事:我不知道您提供的请求是否只是示例,而不是使用方法 plain 将代码验证程序转换为代码挑战,我宁愿使用安全的方法例如 S256 ,而不是您在问题中引用的RFC中的建议。
答案 1 :(得分:1)
这取决于。最初,引入PKCE是为了保护公共客户端(不能保护机密的客户端)。但是在最近的最佳实践中,PKCE成为授权码授予(source)的建议
2.1.1。授权码授予
客户端必须阻止将授权代码注入(重播)到
攻击者的授权响应。 PKCE的使用[RFC7636]
为此被推荐。 OpenID Connect的“ nonce”参数和 ID令牌声明[OpenID]也可以使用。 PKCE挑战还是
OpenID Connect“即刻”必须特定于事务且安全地
绑定到进行交易的客户和用户代理
开始。注意:尽管到目前为止PKCE被设计为一种保护机制
本机应用程序,此建议适用于各种OAuth客户端,
包括网络应用程序。
简而言之,为避免授权代码重播攻击(spec - introduction)。而且这发生在最终用户的设备内部,而不是数据传输中。对于OAuth 2.0令牌请求,必须使用TLS。
由于令牌请求是通过TLS完成的,因此任何授予都不会公开凭据。
在您的情况下,我认为客户是机密客户(spec - client types)。因此,我建议在授权服务器中检查此方面。
答案 2 :(得分:1)
我正在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
,才能在没有access_token
的情况下获得client_secret
。
因此上面的代码将变为:
Doorkeeper::Application.create :name => 'Test App', :uid => 'xxxx', :secret => 'xxxx', :redirect_uri => 'urn:ietf:wg:oauth:2.0:oob', :confidential => false
我在以下位置找到了解决方案: https://github.com/doorkeeper-gem/doorkeeper/blob/master/spec/requests/flows/authorization_code_spec.rb#L348