在Swing中,密码字段有一个getPassword()(returns char[])方法,而不是通常的getText()(return String)方法。同样,我也遇到了一个建议,不要使用String来处理密码。
为什么字符串对密码安全构成威胁?使用char[]感觉不方便。
在Swing中,密码字段有一个getPassword()(returns char[])方法,而不是通常的getText()(return String)方法。同样,我也遇到了一个建议,不要使用String来处理密码。
为什么字符串对密码安全构成威胁?使用char[]感觉不方便。
当前回答
我认为这不是一个有效的建议,但是,我至少可以猜出原因。
我认为动机是希望确保在密码被使用后,您可以及时且确定地删除记忆中的所有密码痕迹。使用char[],您可以用空白或确定的内容覆盖数组的每个元素。不能这样编辑字符串的内部值。
但这并不是一个好答案;为什么不确保对char[]或String的引用不转义?那么就没有安全问题了。但问题是,String对象在理论上可以被内部化,并在常量池中保持活动状态。我想使用char[]禁止这种可能性。
其他回答
大小写字符串:
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
Java中的字符串是不可变的。因此,无论何时创建字符串,它都将保留在内存中,直到被垃圾收集。因此,任何访问内存的人都可以读取字符串的值。
如果字符串的值被修改,那么它将最终创建一个新字符串。因此,原始值和修改后的值都保留在内存中,直到被垃圾收集。
使用字符数组,一旦达到密码的目的,就可以修改或删除数组的内容。在修改数组之后,甚至在垃圾收集开始之前,都不会在内存中找到数组的原始内容。
出于安全考虑,最好将密码存储为字符数组。
字符串是不可变的。这意味着一旦创建了String,如果另一个进程可以转储内存,那么在垃圾收集开始之前,就没有办法(除了反射之外)清除数据。
使用数组,您可以在完成后显式擦除数据。您可以用任何您喜欢的内容覆盖数组,并且密码不会出现在系统中的任何位置,甚至在垃圾收集之前。
是的,这是一个安全问题,但即使使用char[]也只会减少攻击者的机会窗口,而且只针对这种特定类型的攻击。
如注释中所述,垃圾收集器移动的数组可能会在内存中留下数据的零散副本。我认为这是特定于实现的——垃圾收集器可以在运行时清除所有内存,以避免这种情况。即使这样,char[]仍有一段时间包含实际字符作为攻击窗口。
字符串是不可变的,一旦创建就不能更改。将密码创建为字符串将在堆或字符串池中留下对密码的零散引用。现在,如果有人对Java进程进行堆转储并仔细扫描,他可能会猜出密码。当然,这些未使用的字符串将被垃圾收集,但这取决于GC何时启动。
另一方面,一旦完成身份验证,char[]是可变的,您可以用任何字符(如所有M或反斜杠)覆盖它们。现在,即使有人进行了堆转储,他也可能无法获取当前未使用的密码。这在某种意义上为您提供了更多的控制,比如自己清除Object内容,而不是等待GC执行。
前面的很多答案都很好。还有一点我在假设(如果我错了,请纠正我)。
默认情况下,Java使用UTF-16存储字符串。使用字符数组、char[]数组,有助于使用Unicode、区域字符等。该技术允许所有字符集在存储密码时受到同等尊重,因此不会因字符集混淆而引发某些加密问题。最后,使用字符数组,我们可以将密码数组转换为所需的字符集字符串。