【问题标题】:Securing REST Web Service using token (Java)使用令牌 (Java) 保护 REST Web 服务
【发布时间】:2014-08-16 04:01:11
【问题描述】:

这个问题在某种程度上与下面链接的问题有关。但是,我需要更清楚一些方面和一些额外的信息。参考: REST Web Service authentication token implementation

背景:

  • 我需要使用令牌实现 REST Web 服务的安全性
  • Web 服务旨在与 Java 客户端一起使用。因此,形成 凭据的身份验证和弹出窗口没有用。
  • 我是 REST 安全和加密的新手

这是我到现在才明白的:

对于第一个请求:

  1. 用户建立 https 连接(或容器确保 https 使用 301)
  2. 用户将用户名和密码发布到登录服务
  3. 如果凭据有效,我们:
    • 生成随机临时令牌
    • 将随机令牌存储在服务器上,将其映射到实际用户名
    • 使用只有服务器知道的对称密钥加密令牌
    • 散列加密令牌
    • 将加密的令牌和哈希发送给客户端

后续请求:

  1. 客户端发送此加密令牌和哈希组合(使用 基本用户名字段?)
  2. 我们确保加密的令牌不会使用哈希值被篡改,并且 然后解密
  3. 我们检查会话跟踪表中的解密令牌 未过期条目并获取实际用户名(过期待管理 通过代码?)
  4. 如果找到用户名,基于允许的角色,允许的操作 已配置

更多细节:

  1. 由于客户端是java客户端,所以第一个请求可以是POST 包含凭据。但是,这看起来可能会暴露 https 建立之前的凭据。因此应 对安全资源有一个虚拟 GET,因此 https 是 先成立?
  2. 假设上面是必需的,第二个请求是一个 LoginAction POST 有凭据。此请求是手动处理的(不使用 容器的授权)。对吗?
  3. 以上LoginAction返回给用户的加密组合 令牌 + 哈希
  4. 用户将其设置为 BASIC 身份验证使用的标头 机制(字段用户名)
  5. 我们实现一个 JAASRealm 来解密和验证令牌,并找到 允许的角色
  6. 授权过程的其余部分由容器处理 使用 web.xml 中定义的 WebResourceCollection

这是正确的方法吗?

【问题讨论】:

    标签: java web-services security rest encryption


    【解决方案1】:

    为什么不将其简化为以下?

    对于第一个请求:

    1. 用户建立到服务器的 HTTPS 连接(服务不监听任何 其他端口)并将凭据发布到登录服务。
    2. 服务器回复HSTS header 以确保所有进一步的通信 是 HTTPS。
    3. 如果凭据有效,我们:
      • 生成一个使用CSPRNG 安全生成的随机临时令牌。使其足够长以确保安全(128 位)。
      • 将随机令牌存储在服务器上,将其映射到实际用户名。
      • 向客户端发送随机令牌

    后续请求:

    1. 客户端通过 HTTPS 在自定义 HTTP 标头中发送令牌。
    2. 令牌位于数据库中并映射到用户名。如果找到,则根据允许的角色和允许的操作配置访问权限。
    3. 如果未找到,则认为用户未经身份验证,必须再次通过登录服务进行身份验证才能获取新令牌。

    在服务器端,令牌将与到期日期一起存储。在每次访问该服务时,该日期将被更新以创建一个滑动到期。将有一个作业每隔几分钟运行一次以删除过期的令牌,并且检查令牌是否有效会话的查询将只检查那些尚未被视为已过期的作业(如果计划的作业因任何原因失败,则防止永久会话)。

    不需要散列加密数据库中的令牌 - 除了security through obscurity 之外,它不会增加任何实际价值。你可以只是散列。这将防止设法获取会话数据表的攻击者劫持现有用户会话。

    【讨论】:

    • 感谢您提供的许多优点。我将跳过令牌加密,因为它似乎没有什么价值。您能否建议是否有办法在 Servlet 容器中使用 BASIC 身份验证使用的某些特定 http 标头?我想在将来的请求中使用类似于用户名的令牌。因此,该解决方案可以与 servlet 容器的授权设施相结合。任何特定的标题?另外,我是否应该为“用户名”验证(后续请求)编写自定义领域或其他内容
    • @Teddy:如果您希望它与仅适用于基本身份验证的组件一起使用,那么您需要发送实际的 Authorization 标头。这实际上是 username:password 的哈希值,将 usernamepassword 替换为实际值 - 如果密码实际上是用户的密码,这不是很安全,因为它在所有会话中都是静态的。如果您可以将password 设置为您的令牌,那就太好了。您实际上并不需要用户名字段,因为令牌将是会话和帐户的唯一标识符。
    • 额外使用nonce来避免重放攻击。
    • @SilverlightFox 你给我的信息真的很好。我不知道。
    【解决方案2】:

    方法看起来不错。不是很安全。 让我重点介绍一下该请求可能造成的一些攻击。

    1. POST 请求中的中间人攻击,用户可以篡改请求,而服务器没有任何办法确保数据不被篡改。

    2. 重放攻击:在这种情况下,攻击者不会篡改请求。攻击者在短时间内多次点击请求并将其发送到服务器,虽然这是一个有效请求,但服务器多次处理该请求,这是不需要的 请阅读 Nonce。

    3. 在第一步中,用户将其凭据(即用户名和密码)发送到登录服务,如果您有一个基于 Web 的应用程序也使用相同的密码,则可能很危险。如果万一密码泄露,API 和 Web 的一切都暴露了,请使用不同的 PIN 进行 API 访问。此外,请确保您指定的解密令牌在一定时间后过期。

    4. 确保服务(应用程序服务器)tomcat。如果发生内部错误,jboss 永远不会返回服务器页面,这会为攻击者提供部署应用程序的服务器的额外信息。

    -- 根据第二个帖子修改--
    是的,如果您使用相互 SSL,那么您是正确的,但如果它是一种单向访问,则您没有客户端证书。如果您只是双重确保请求中的所有内容,就像签名(签名)SOAP(一种强大的数据传输机制)一样,那将是一件好事。但是重放攻击是 HTTPS 的一种可能性,只需处理它。休息使用令牌加密很好。为什么不要求客户端使用密码解密令牌并返回解密的输出,如果它存在于您的数据库中,您可以验证输出?这种方法即使是HTTPS,用户也不会通过网络发送密码?

    【讨论】:

    • 据我了解,基于 HTTPS 的 POST 不会受到您提到的许多问题的影响。见security.stackexchange.com/a/53621security.stackexchange.com/a/53605
    • 是的,如果您使用相互 SSL,则您是正确的,但如果它是一种单向访问,则您没有客户端证书。如果您只是双重确保请求中的所有内容,就像签名(签名)SOAP(一种强大的数据传输机制)一样,那将是一件好事。但是重放攻击是 HTTPS 的一种可能性,只需处理它。其余使用令牌加密很好。
    猜你喜欢
    • 2014-04-05
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 2013-01-19
    • 2017-07-12
    • 2012-02-15
    • 1970-01-01
    相关资源
    最近更新 更多