在创建帐户时,如何在内存中安全地存储密码?

我们的基于Web的应用程序使用帐户创建期间指定的密码将用户帐户绑定到用户。 在Java的情况下,在将哈希值保存在数据库中之前,如何安全地处理密码。

更具体地说,如何确保持有密码的字符串在足够短的时间间隔内被垃圾收集?

如果您有可能(在Web应用程序中可能很难),最好将密码存储在字符数组中,而不是将它们存储在字符串中。 如果您已完成存储密码,则可以使用Array.fill()在内存中覆盖它,并通过丢弃它来为垃圾收集器提供引用:

Arrays.fill(password, ' '); password = null; 

我只是注意到取消密码会有点偏执,但如果它让你放心,你可以这样做:)

您不使用String。 使用char []然后在完成后覆盖char []。

在垃圾收集方面绝对没有保证(除了终结器将在收集对象之前运行)。 GC可能永远不会运行,如果它运行它可能永远不会GC具有密码的字符串。

如果您在客户端创建哈希,则不需要考虑此问题。 普通密码永远不会提交给服务器。

两个词:本地范围。 用于密码处理的声明变量需要具有绝对最小的范围。

一旦变量超出范围,对象就有资格进行垃圾回收。

通常,你会从请求中挑选出来的东西。 您需要一个非常非常小的事务来接受请求,哈希密码,持久化并重定向。 然后,您重定向的页面可以获取内容并执行作为应用程序一部分的所有“其他”处理。

无法保证在Java中从内存中删除明文密码。

但是,黑客不需要访问程序的内存来获取明文密码。 有更简单的方法(例如嗅探数据包),所以任何人都不太可能依赖这种方法。

最好的方法是让客户端加密密码,如@ Mork0075建议的那样。 但是,虽然这意味着您无法轻松获取密码,但程序仍然可以获取密码的加密版本,因此假装是用户。 解决此问题的方法是使用SSL加密整个连接。

所有这些都是学术性的,因为黑客最简单的方法是监视数据包的数据包并获取数据库的密码。 我怀疑直接访问您的数据库更关注……或者可能不是。 ;)

使用密码挑战:

  1. 服务器选择质询值并将其发送给客户端
  2. 服务器使用密码和挑战执行单向转换,例如。 MD5(CONCAT(challenge, password))并将其分配给会话。
  3. 纯文本密码现在已超出范围,可以进行垃圾回收。
  4. 客户端也执行相同的转换并将结果发送到服务器。
  5. 如果服务器和客户端选择相同的最终值,则对客户端进行身份validation。

此方法可防止重放攻击 ,但要求挑战值非常不可预测(随机)且不经常重复使用(长)。

在处理初始连接请求期间,纯文本密码仅在范围内 – 而不是在身份validation期间。 单向转换结果在范围内(不是垃圾收集)的长度并不重要,因为它几乎没有重放值。