在Swing中,密码字段有一个getPassword()(returns char[])方法,而不是通常的getText()(return String)方法。同样,我也遇到了一个建议,不要使用String来处理密码。

为什么字符串对密码安全构成威胁?使用char[]感觉不方便。


当前回答

字符串是不可变的,一旦创建就不能更改。将密码创建为字符串将在堆或字符串池中留下对密码的零散引用。现在,如果有人对Java进程进行堆转储并仔细扫描,他可能会猜出密码。当然,这些未使用的字符串将被垃圾收集,但这取决于GC何时启动。

另一方面,一旦完成身份验证,char[]是可变的,您可以用任何字符(如所有M或反斜杠)覆盖它们。现在,即使有人进行了堆转储,他也可能无法获取当前未使用的密码。这在某种意义上为您提供了更多的控制,比如自己清除Object内容,而不是等待GC执行。

其他回答

前面的很多答案都很好。还有一点我在假设(如果我错了,请纠正我)。

默认情况下,Java使用UTF-16存储字符串。使用字符数组、char[]数组,有助于使用Unicode、区域字符等。该技术允许所有字符集在存储密码时受到同等尊重,因此不会因字符集混淆而引发某些加密问题。最后,使用字符数组,我们可以将密码数组转换为所需的字符集字符串。

有些人认为,一旦您不再需要密码,就必须覆盖用于存储密码的内存。这缩短了攻击者从系统读取密码的时间窗口,并完全忽略了这样一个事实,即攻击者已经需要足够的访问权限来劫持JVM内存。具有如此多访问权限的攻击者可以捕获您的关键事件,使其完全无用(AFAIK,所以如果我错了,请纠正我)。

使现代化

感谢这些评论,我不得不更新我的答案。显然,在两种情况下,这可以增加(非常)轻微的安全改进,因为它可以减少密码在硬盘上的时间。但我仍然认为这对大多数用例来说都是过度的。

您的目标系统可能配置不正确,或者您必须假设它是错误的,并且您必须对核心转储(如果系统不是由管理员管理的,则可能是有效的)心存疑虑。您的软件必须过于偏执,以防止攻击者使用TrueCrypt(已停产)、VeraCrypt或CipherShed等工具访问硬件时发生数据泄漏。

如果可能,禁用内核转储和交换文件可以解决这两个问题。然而,它们需要管理员权限,可能会减少功能(使用的内存更少),从运行系统中取出RAM仍然是一个值得关注的问题。

大小写字符串:

    String password = "ill stay in StringPool after Death !!!";
    // some long code goes
    // ...Now I want to remove traces of password
    password = null;
    password = "";
    // above attempts wil change value of password
    // but the actual password can be traced from String pool through memory dump, if not garbage collected

案例CHAR阵列:

    char[] passArray = {'p','a','s','s','w','o','r','d'};
    // some long code goes
    // ...Now I want to remove traces of password
    for (int i=0; i<passArray.length;i++){
        passArray[i] = 'x';
    }
    // Now you ACTUALLY DESTROYED traces of password form memory

我认为这不是一个有效的建议,但是,我至少可以猜出原因。

我认为动机是希望确保在密码被使用后,您可以及时且确定地删除记忆中的所有密码痕迹。使用char[],您可以用空白或确定的内容覆盖数组的每个元素。不能这样编辑字符串的内部值。

但这并不是一个好答案;为什么不确保对char[]或String的引用不转义?那么就没有安全问题了。但问题是,String对象在理论上可以被内部化,并在常量池中保持活动状态。我想使用char[]禁止这种可能性。

字符串是不可变的,一旦创建就不能更改。将密码创建为字符串将在堆或字符串池中留下对密码的零散引用。现在,如果有人对Java进程进行堆转储并仔细扫描,他可能会猜出密码。当然,这些未使用的字符串将被垃圾收集,但这取决于GC何时启动。

另一方面,一旦完成身份验证,char[]是可变的,您可以用任何字符(如所有M或反斜杠)覆盖它们。现在,即使有人进行了堆转储,他也可能无法获取当前未使用的密码。这在某种意义上为您提供了更多的控制,比如自己清除Object内容,而不是等待GC执行。