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

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


当前回答

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

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崩溃并生成内存转储时,您将能够看到密码。

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

其他回答

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

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

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

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

字符数组(char[])可以在使用后通过将每个字符设置为零而不设置为字符串来清除。如果有人能够以某种方式看到内存映像,那么如果使用字符串,他们可以看到纯文本的密码,但是如果使用char[],则在用0清除数据后,密码是安全的。

大小写字符串:

    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

编辑:经过一年的安全研究后,我回到了这个答案,我意识到这意味着你可能会比较明文密码。请不要。使用一个安全的单向散列和一个合理的迭代次数。考虑使用图书馆:这东西很难弄对!

原始答案:String.equals()使用短路求值,因此容易受到定时攻击,这一事实如何?这可能不太可能,但理论上可以对密码比较计时,以确定正确的字符序列。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // Quits here if Strings are different lengths.
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // Quits here at first different character.
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

关于定时攻击的更多资源:

定时攻击的教训关于信息安全堆栈交换上定时攻击的讨论当然,定时攻击维基百科页面

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

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

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