5

我正在构建 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"

现在问题来了,为了交换codeaccess_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."
}

所以这是我的问题:

  1. 我们真的需要client_secret进入access_tokenPKCE 流程吗?
  2. 为什么建议使用“PKCE Flow”,如果它只会暴露client_secret
  3. 它与同样公开的“客户凭证授予流程”有何不同client_secret

Doorkeeper PKCE 文档:https ://github.com/doorkeeper-gem/doorkeeper/wiki/Using-PKCE-flow

4

3 回答 3

6

更新


与此同时,建议发生了变化(另请参阅 Kavindu 的答案以获取参考资料),我想确保在此答案中也强调了这一点。将PKCE作为客户端机密的附加安全补充层对机密客户端也很有意义。客户端密钥允许授权服务器(身份提供者)确定客户端的身份

虽然 PKCE 允许确保尝试为令牌交换授权码的一方是首先实际请求授权码的一方。因此,为了避免拦截场景,即使对于机密客户端,它也可以在顶部添加 PKCE。

但请记住,并非所有身份提供者都可能支持同时使用 PKCE 和客户端密钥(目前)。

至于门卫所述的问题,这种行为可能同时也发生了变化。


原始答案


PKCE 的授权代码流是为客户端无法安全保护机密的设置而发明的。因此,在将授权代码流与 PKCE 一起使用时,您不需要秘密,或者更准确地说,客户端秘密没有任何意义。

似乎您遇到的是Doorkeeper 错误(请参阅https://github.com/doorkeeper-gem/doorkeeper/issues/1089)。所以我担心在他们修复它之前你将不得不使用一些虚拟的客户秘密。

但只要 Doorkeeper 正确实现了 PKCE 流程的其余部分,这应该不是问题,因为此流程不依赖于任何静态客户端机密,而是使用您已经指出的动态创建的代码验证器。

我不确定我是否正确理解您使用的处理登录的客户端类型。如果它是 SPA 或移动应用程序,您应该使用带有 PKCE 的授权代码流,但如果您正在实现一个“经典”Web 应用程序,其中在某些后端服务中处理登录,您应该使用客户端密码使用正常的授权代码流作为可以信任后端来保护机密。

顺便说一句,我刚刚检查了我正在处理的一个项目中的代码,我在其中构建了一些 Angular SPA,该 SPA 通过 Auth0 作为身份提供者进行身份验证。我在那里使用带有 PKCE 的授权代码流,我绝对不会向 Auth0 发送任何客户端密码,因为显然该流是按预期实现的。所以这确实是Doorkeeper的一个问题。

另一件事:我不知道您提供的请求是否只是示例,而不是使用普通方法将代码验证器转换为代码挑战,我宁愿使用安全方法,例如S256,而不是按照 RFC 中的建议你在你的问题中提到。

于 2020-07-27T22:43:22.267 回答
3
  1. 我们真的需要 client_secret 来获取 PKCE 流上的 access_token 吗?

这取决于。最初引入 PKCE 是为了保护公共客户端(无法保护机密的客户端)。但最近,随着实践,PKCE 成为授权代码授予的推荐(来源

2.1.1。授权码授予

客户端必须防止攻击者将授权代码注入(重放)到
授权响应中。为此建议使用 PKCE [RFC7636]
。OpenID Connect "nonce" 参数和 ID Token Claim [OpenID] 也可以使用。PKCE 质询或
OpenID Connect “nonce”必须是特定于事务的,并且安全地
绑定到客户端和
启动事务的用户代理。

注意:尽管到目前为止 PKCE 被设计为一种保护
本地应用程序的机制,但此建议适用于所有类型的 OAuth 客户端,
包括 Web 应用程序。

  1. 如果它只会暴露 client_secret,为什么建议使用“PKCE Flow”?

总之,避免授权码重放攻击(规范-介绍)。这发生在最终用户的设备内部,而不是数据传输中。OAuth 2.0 令牌请求必须使用 TLS。

  1. 它与也公开了 client_secret 的“客户端凭据授予流程”有何不同?

由于令牌请求是通过 TLS 完成的,因此任何授权都不会公开凭据。

我认为在您的情况下,客户是机密客户(规范 - 客户类型)。所以我建议在授权服务器中检查这方面。

于 2020-07-23T17:12:09.667 回答
1

Doorkeeper::Application在 Rails 控制台中创建一个这样的:

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

于 2020-07-24T09:36:05.077 回答