3

情况:

  • 具有基于用户名/密码的用户身份验证的 java EE Web 应用程序
  • 密码验证不是由应用程序本身完成的。它使用HttpServletRequest.login()并且安全领域在应用服务器中定义。
  • 应用程序使用授权(@RolesAllowed 注解)
  • 应用程序允许用户被记住,因此他不需要每次都进行身份验证

我认为这对于 Web 应用程序来说是相当普遍的要求,但最后一个要求并不是那么容易实现,而且我还没有找到实现它的标准方法。我喜欢展示我的想法并解释为什么我认为它们并不完美。

1 保持 HttpSession 打开
实际上这是我最喜欢的方式。我认为使用HttpSessioin.setMaxInactiveInterval()可以解决问题。基本上是这样,但是如果没有正确清理会话并且您有很多用户,这可能是资源问题。在这里我自己的问题表明清理 HttpSession 并不容易。

2 使用“记住我”cookie
为什么不只生成一个 UUID 并将其作为 cookie 发送,而不是在 HttpSession 是新的时检查它。如果安全领域的唯一用途是检查用户名/密码,这将非常有效。如果使用授权或getUserPrincipal()之类的函数,则不可能。我还没有找到一种方法来使用HttpServletRequest.login()或带有令牌而不是密码的类似函数。

3 使用“记住我”cookie 并使用我自己的授权
嗯,当然,这是可能的,但我喜欢限制对某些 bean 或方法的访问的简单方法。这让我更难实现用户可以访问他不应该访问的东西的东西。

4 使用带有密码的“记住我”cookie
愚蠢!下一个!

5 使用“记住我”cookie 并保留密码
这个想法是记住密码和与 cookie 的关系,因此 HttpServletRequest.login() 可以与密码一起使用。这是此答案中解释的方法:https
://stackoverflow.com/a/5083809/210380 我认为这种方法有一个大问题:永远不要存储未加密的密码
人们可以考虑将密码保存在内存中,但我没有也不喜欢。该应用程序可以在任何地方使用,如果公司的所有密码都被泄露,我不想负责,因为有人临时访问服务器并进行了内存转储。

我目前的解决方案
基于这些想法,我想出了自己的解决方案。我正在使用两个cookie。第一个只是一个“记住我”的 cookie,带有UUID的 String 表示。此 UUID 也与用户名一起被记住在内存或数据库中。第二个 cookie 还包含 UUID 的字符串表示形式,用于加密密码。加密密码与数据库或内存中第一个 cookie 的 UUID 一起被记住。不会保留第二个 cookie 中的 UUID。不在数据库中,也不在内存中。要加密和解密用户密码,我使用来自 jasypt 的 StandardPBEStringEncryptor
当用户尝试使用此 cookie 重新进行身份验证时,我会同时读取它们,根据第一个 cookie 搜索用户名和加密密码,使用第二个 cookie 解密密码并使用带有用户名和密码的 HttpServletRequest.login()。然后我删除存储在服务器上的加密密码,并使用两个新的 UUID 重新启动该过程。

问题

  1. 真的没有标准化的解决方案吗?

  2. 我的解决方案中是否存在我看不到的安全问题?
    例如,在重新认证时使用新密钥加密密码是否不明智?

  3. StandardPBEStringEncryptor 是这个任务的好选择吗?

  4. 我的解决方案是否矫枉过正,我在浪费时间?

谢谢

4

1 回答 1

0
  1. servlet API 中确实没有“记住我”的标准。
  2. 我相信您的解决方案更容易受到 cookie 窃取的影响,因为您的第二个 UUID 用于加密密码并存储在 cookie 中。这个答案显示了通常保存在登录 cookie 中的内容。
  3. 双向加密真的有必要吗?一种加密方式更简单,更容易处理。根据您的应用程序安全要求,SHA-512 以上的任何内容都是合适的散列算法。
  4. 我建议你看看 Apache Shiro。它支持记住我,使用多种算法(只有一种方式,但我不确定)的加盐密码散列和@RolesAllowed类似安全拦截器。

如果您选择 Shiro,本教程将非常彻底和完整。您还可以在 shiro.apache.org 查看官方文档

于 2014-02-24T22:52:17.503 回答