在Swing中,密码字段有一个getPassword()(returns char[])方法,而不是通常的getText()(return 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

其他回答

字符串是不可变的,它将进入字符串池。一旦写入,就无法覆盖。

char[]是一个数组,当您使用密码时,应该覆盖该数组,这是应该这样做的:

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
  allowUser = true;
  cleanPassword(passw);
  cleanPassword(dbPassword);
  passw = null;
}

private static void cleanPassword (char[] pass) {

  Arrays.fill(pass, '0');
}

攻击者可以使用它的一种情况是,当JVM崩溃并生成内存转储时,您将能够看到密码。

这不一定是恶意的外部攻击者。这可能是一个支持用户,可以访问服务器进行监控。他/她可以偷看垃圾堆并找到密码。

虽然这里的其他建议似乎有效,但还有一个很好的理由。使用纯字符串时,意外将密码打印到日志、监视器或其他不安全的地方的可能性要大得多。char[]不那么脆弱。

考虑一下:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

打印:

String: Password
Array: [C@5829428e

是否应该使用String或Char[]来实现这一目的是有争议的,因为两者都有各自的优点和缺点。这取决于用户需要什么。

由于Java中的字符串是不可变的,所以每当有人试图操纵字符串时,它会创建一个新的Object,而现有的字符串不会受到影响。这可以被视为将密码存储为字符串的一个优点,但即使在使用后,该对象仍保留在内存中。因此,如果有人以某种方式获得了对象的内存位置,那么此人可以很容易地跟踪存储在该位置的密码。

Char[]是可变的,但它的优点是在使用后,程序员可以显式地清理数组或重写值。因此,当它被使用后,它会被清理干净,没有人会知道你存储的信息。

基于以上情况,我们可以根据他们的需求来决定是使用String还是使用Char[]。

字符串是不可变的。这意味着一旦创建了String,如果另一个进程可以转储内存,那么在垃圾收集开始之前,就没有办法(除了反射之外)清除数据。

使用数组,您可以在完成后显式擦除数据。您可以用任何您喜欢的内容覆盖数组,并且密码不会出现在系统中的任何位置,甚至在垃圾收集之前。

是的,这是一个安全问题,但即使使用char[]也只会减少攻击者的机会窗口,而且只针对这种特定类型的攻击。

如注释中所述,垃圾收集器移动的数组可能会在内存中留下数据的零散副本。我认为这是特定于实现的——垃圾收集器可以在运行时清除所有内存,以避免这种情况。即使这样,char[]仍有一段时间包含实际字符作为攻击窗口。

简单明了的答案是因为char[]是可变的,而String对象不是可变的。

Java中的字符串是不可变的对象。这就是为什么它们一旦创建就不能被修改,因此从内存中删除它们的内容的唯一方法就是垃圾收集。只有当对象释放的内存可以被覆盖时,数据才会消失。

现在,Java中的垃圾收集不会在任何保证的时间间隔内发生。因此,字符串可以在内存中保存很长时间,如果在此期间进程崩溃,字符串的内容可能会在内存转储或某些日志中结束。

使用字符数组,您可以读取密码,尽快完成处理,然后立即更改内容。