关于安全性:为什么我不应该将client_secret保留在OAuth 2.0的移动应用程序中(授权码授予流程)

Why I shouldn't keep client_secret in mobile app in OAuth 2.0 (authorization code grant flow)

我们有一个应用程序,该应用程序应通过作为授权服务器的第三方OAuth 2.0服务器使用身份验证。

据我了解,有两种可能性。

"正确"的是:

  • 移动应用程序商店client_id
  • 移动应用以GET / auth开头以接收authorization_code
  • 授权服务器返回带有重定向到redirect_uri的响应
    和附加的授权码。我们假设redirect_uri是一个
    我们自己的服务器上的端点。
  • 移动应用遵循重定向
  • 我们的服务器收到请求,从查询中获取授权码,
    使用POST / token方法将其交换为access_token
    client_secret(存储在服务器上)。
  • 服务器对具有access_token的移动应用程序的响应
  • 移动应用获取access_token并将其用于将来的请求。
  • "坏"的是:

  • 移动应用程序存储client_id和client_secret
  • 移动应用以GET / auth开头以接收authorization_code
  • 授权服务器返回带有重定向到redirect_uri的响应
    和附加的授权码。我们假设那个应用
    拦截它并获取authorization_code(我们可以简单地要求
    重定向到本地主机)。
  • 移动应用使用POST / token方法将其交换为access_token
    和client_secret。
  • 移动应用将获取access_token并将其用于以后的所有请求中。
  • 所以我看不到这两种选择之间的真正区别。在这两种情况下,我们最终都会获得访问令牌。在这两种情况下,我们都需要真实用户在相当安全的Web视图中输入其登录名和密码。

    即使某些坏蛋会分发伪造的应用程序...是什么禁止他们使用我们服务器的回调函数交换access_token的授权代码?我们的服务器无法区分"不良"和"良好"应用程序-它仅接收请求GET \ callback?code = blablabla并使用access_token进行回复。

    那么,为什么我们要对服务器保密呢?假冒应用程序的欺诈情况如何?


    使用OAuth,您可以根据需要/设置使用不同的流程。根据不同的流程,OAuth角色的行为也将有所不同。

    从您的描述中,我不确定要在客户角色中扮演什么角色。但是选项是:

  • 后端服务器是客户端
  • 移动应用是客户
  • 对于情况1,您不需要在应用程序中存储客户端ID或客户端密钥,因为它将是您自己的后端服务器,可以与授权服务器和资源服务器进行通信。如果是这种情况,那么您可以遵循授权码流程。

    对于案例2,将由应用程序本身与授权和资源服务器进行通信。在这种情况下,建议使用隐式流。它不被视为安全流程,移动设备或Web应用也不被视为存储客户端密钥的安全位置,因为您必须以某种方式将它们存储在应用的代码中。
    下面是一个(有点费解的)方案来解释为什么这种方法不安全:客户端机密由授权服务器或服务注册表发布,任何黑客攻击都需要您对其进行更改,这可能意味着更改代码。对于移动应用程序,这意味着您的用户将更新到新版本。
    普遍认为,作为一种额外的安全性步骤(而不是客户端机密),建议使用"状态"或"随机数"字段来确保授权请求来自与发出令牌的应用程序相同的应用程序。
    从RFC第4.1.1节(http://tools.ietf.org/html/rfc6749#section-4.1.1):

    state

    1
    2
    3
    4
    5
         RECOMMENDED.  An opaque value used by the client to maintain
         state between the request and callback.  The authorization
         server includes this value when redirecting the user-agent back
         to the client.  The parameter SHOULD be used for preventing
         cross-site request forgery as described in Section 10.12.

    要在状态字段中传递的值取决于提出请求的人。您可以生成一个随机(或伪随机)数字。授权服务器发回的答复将完全填充客户端发送状态字段的状态字段。然后,您可以将收到的状态字段与发送的字段匹配,以查看它们是否匹配。

    您可以采取的另一步骤是让客户端发送带有令牌请求的重定向URI。这很有用,以便授权服务器可以验证请求中的重定向URI是否与它与客户端ID关联的重定向URI匹配。如果您使用的是第三方授权服务器,则应检查它是否具有此行为。

    作为最终的安全建议,与授权服务器或资源服务器通信时,请始终与HTTPS一起使用。

    这篇文章很好地说明了OAuth的不同流程:https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2


    1
    We assume, that redirect_uri is an endpoint on our own server.

    我相信您在这里混淆了客户端和资源服务器的角色。你的
    资源服务器(托管API的服务器)当然永远不要将令牌返回给移动应用程序(客户端),因为它首先需要该令牌来认证客户端。

    在OAuth2中,客户端应在与资源服务器进行通信之前从授权服务器获取令牌。

    它可以使用隐式授权或授权码授权。在后一种情况下,它应在不提供客户机密的情况下使用授权,因为移动客户端被视为无法安全存储机密的公共客户端。