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

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


当前回答

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

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

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

其他回答

答案已经给出了,但我想与大家分享一下我最近在Java标准库中发现的一个问题。尽管他们现在非常小心地将密码字符串替换为随处可见的char[](这当然是一件好事),但在从内存中清除密码时,其他安全关键数据似乎被忽略了。

我正在考虑例如PrivateKey类。考虑一个场景,您将从PKCS#12文件加载一个专用RSA密钥,并使用它执行一些操作。现在,在这种情况下,只要对密钥文件的物理访问受到适当限制,单独嗅探密码对您没有多大帮助。作为一名攻击者,如果您直接获得密钥而不是密码,您的情况会更好。所需的信息可能是多方面的泄漏,核心转储、调试器会话或交换文件只是一些示例。

事实证明,没有任何东西可以让您从内存中清除PrivateKey的私有信息,因为没有API可以让您擦除构成相应信息的字节。

这是一个糟糕的情况,因为本文描述了这种情况如何被潜在利用。

例如,OpenSSL库在释放私钥之前会覆盖关键内存段。由于Java是垃圾收集的,所以我们需要显式方法来清除Java密钥的私有信息并使其无效,这些私有信息将在使用密钥后立即应用。

Java中的字符串是不可变的。因此,无论何时创建字符串,它都将保留在内存中,直到被垃圾收集。因此,任何访问内存的人都可以读取字符串的值。

如果字符串的值被修改,那么它将最终创建一个新字符串。因此,原始值和修改后的值都保留在内存中,直到被垃圾收集。

使用字符数组,一旦达到密码的目的,就可以修改或删除数组的内容。在修改数组之后,甚至在垃圾收集开始之前,都不会在内存中找到数组的原始内容。

出于安全考虑,最好将密码存储为字符数组。

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

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

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

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

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

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

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

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