【问题标题】:What is secure way to send request to /oauth/token in Spring Security?在 Spring Security 中向 /oauth/token 发送请求的安全方式是什么?
【发布时间】:2019-05-01 20:22:54
【问题描述】:

从客户端应用发送请求以获取访问令牌的理想/安全方式是什么?

我有一个 REST API(使用 Spring Boot 开发),由该 API 的客户端应用程序(使用 React.js 开发)使用。例如,Stackoverflow 有后端 API,它的前端客户端使用该 API。 REST API 使用 OAuth2 进行保护。

API 返回访问令牌的端点是

http://192.168.43.70:8085/api/v1/oauth/token?grant_type=password&username=22@gmail.com&password=mypassword

连同客户端密码。这是来自 React.js 的请求:

axios
    .create({
      baseURL:
        "http://192.168.43.70:8085/api/v1/oauth/token?grant_type=password&username=22@gmail.com&password=mypassword",
      auth: {
        username: "my-client",
        password: "ZS10ZXN0"
      }
    })

这是正确的方法吗,因为我们将客户端机密("my-client""bGl2ZS10ZXN0")暴露给浏览器,任何人都可以从浏览器中看到用于此请求的客户端凭据?

【问题讨论】:

    标签: reactjs spring-boot axios spring-security-oauth2


    【解决方案1】:

    你说得对,这是不安全的,不建议这样做。最好使用不需要客户端凭据的不同授权流程。

    我建议您查看authorization_code 授权流程(没有客户端密码)而不是密码授权流程。 resources 中的 couple 将为您提供有关为什么不使用密码流程的更多背景信息,但首先简要介绍一下:

    从网页加载 Javascript 和 HTML 源代码后,单页应用程序(或基于浏览器的应用程序)完全在浏览器中运行。由于浏览器可以使用整个源,因此它们无法维护客户端机密的机密性,因此机密不用于这些应用程序。 流程与授权码流程完全相同,但在最后一步,将授权码交换为访问令牌,而不使用客户端密码。

    不过,更好的是,如果您可以引入一个通过 JSESSIONID(意味着更改为会话后端)与您的客户端协商的服务器端组件,那么我相信您会找到secrets are much easier to maintain on the backend。你可以看看Spring Security's OAuth 2.0 Client support

    【讨论】:

    • 但是,JSESSIONID 不是打破了 RESTfull 架构的Stateless 约束吗?我认为是的。
    • @TheCoder,是的,没错。我已经在答案中阐明了使用 JSESSIONID 的含义。我还添加了一个链接,为这一点添加了一些细节。
    【解决方案2】:

    资源所有者密码凭据授予不是您的应用程序的正确授予类型,请参阅RFC 6749

    4.3.资源所有者密码凭据授予

    资源所有者密码凭据授予类型适用于资源所有者与客户端具有信任关系的情况,例如设备操作系统或高权限应用程序。授权服务器在启用此授权类型时应特别小心,并且仅在其他流程不可行时才允许它。

    您可以使用隐式授权,请参阅RFC 6749

    4.2.隐式授予

    隐式授权类型用于获取访问令牌(它不支持发布刷新令牌),并针对已知操作特定重定向 URI 的公共客户端进行了优化。这些客户端通常使用 JavaScript 等脚本语言在浏览器中实现。

    [...]

    隐式授权类型不包括客户端身份验证,并且依赖于资源所有者的存在和重定向 URI 的注册。由于访问令牌被编码到重定向 URI 中,它可能会暴露给资源所有者和驻留在同一设备上的其他应用程序。

    但由于安全问题,一些授权服务器不支持它。 Spring Security OAuth2 支持它。

    您也可以使用授权码授予,尽管它已针对机密客户进行了优化,请参阅RFC 6749

    4.1.授权码授予

    授权码授权类型用于获取访问令牌和刷新令牌,并针对机密客户端进行了优化。

    [...]

    如果客户端类型是机密的或客户端已获得客户端凭据(或分配了其他身份验证要求),则客户端必须按照第 3.2.1 节所述向授权服务器进行身份验证。

    但由于安全问题,一些授权服务器不支持它。 Spring Security OAuth2 的默认配置需要客户端认证。

    另一种方法是使用 PKCE 授予授权码,请参阅 RFC 7636

    OAuth 公共客户端代码交换的证明密钥

    摘要

    使用授权码授予的 OAuth 2.0 公共客户端容易受到授权码拦截攻击。本规范描述了攻击以及通过使用代码交换证明密钥(PKCE,发音为“pixy”)来减轻威胁的技术。

    但 Spring Security 不支持,请参阅 4943

    【讨论】:

    • 请注意,许多授权服务器有意不实现隐式流程——相反,使用没有客户端密码的授权代码流程被视为隐式的更好替代方案:“实际上,只有在非常有限的情况下这是必要的。几个主要的实现(Keycloak、德国电信、Smart Health IT)选择完全避免隐式流程并使用授权码流程。 - oauth.com/oauth2-servers/single-page-apps
    • 这里有一个链接,我发现它有助于解释为什么像 oauth.com 和 auth0.com 这样的网站不推荐 PKCE 用于 SPA:security.stackexchange.com/questions/182873/…
    • @jzheaux 真正的问题是你可以在互联网上找到任何意见。这就是我尝试坚持规范 (RFC) 的原因。该规范不是基于主要意见的。这也是原因,我没有推荐任何东西。
    • @jzheaux 参见草稿OAuth 2.0 for Browser-Based Apps
    • @jzheaux 我编辑了我的答案以使其更清楚,我不推荐任何东西。我还为 Spring Security OAuth2 的现有问题添加了一些解释。
    猜你喜欢
    • 2021-10-21
    • 2016-05-20
    • 2023-03-08
    • 2018-04-26
    • 1970-01-01
    • 2011-10-29
    • 2020-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多