当使用JDBC时,密码应该使用String还是char[]?

3

从安全角度考虑,最佳实践是不要使用String来存储密码,而是用char[]。这适用于任何时候使用密码吗?例如,使用JDBC时使用String保存密码是否可接受?

public final void Login(String username, String password){
...
conn = DriverManager.getConnection(url, username, password);
...
}

或者在这里可以使用char[]来替换String吗?

你不应该使用String来存储敏感数据,因为Java中的字符串存储方式。char[]通常更安全。 - Kon
1
指南2-2:不要记录高度敏感的信息某些信息,例如社会安全号码(SSN)和密码,是高度敏感的。这些信息不应该保留超过必要的时间,也不应该出现在可能被管理员查看的地方。例如,它不应该被发送到日志文件中,并且其存在不应通过搜索可检测到。一些短暂的数据可以保存在可变数据结构中,例如char数组,并在使用后立即清除。但我不知道如何在我给出的示例中使用char[]代替字符串。 - user3055593
重要的是要确定你所指的是“密码”还是“密钥”。 “密码”通常是字符数据,最好表示为字符串。而“密钥”则是二进制数据,应该是字节数组或类似的东西。 - Hot Licks
2
@Kon - 字符串和字符数组之间的“安全性”差异微不足道。它们的内部表示基本相同。 - Hot Licks
2个回答

3

我不认同你的前提,即在系统资源(例如JDBC数据库连接)的上下文中,char []比String更安全。无论如何,您可以使用连接管理器(或连接池,适用于您的容器),然后连接管理器(仅连接管理器)可以看到底层数据库用户名/密码。


3
我不确定我同意你的前提,即 char[] 比 String 更安全。你应该知道,数组元素可以被覆盖,而字符串存储在字符串池中。 - Jeroen Vannevel
1
有很多关于为什么不要在密码中使用字符串的文章。最好先浏览一下它们。 - kosa
3
如果它是在运行时加载并被用户代码访问...它有多安全? - Elliott Frisch
3
@JeroenVannevel - 是的,理论上可以覆盖 char[]。而且,在它被覆盖之前,它可以被复制到各种内存池中,因此使得覆盖变得毫无意义。如果某些东西可以访问 jvm 内存,那么你已经失去了所有的安全性... - jtahlborn
2
@jtahlborn ...优化器可以消除永远不会被读取的写入操作... - Holger
显示剩余2条评论

1
Java中的字符串是不可变的,一旦创建后就无法更改,因此每当我们说 String s="abc"; s="def"; 它们不引用同一个字符串,而是创建了"abc"字符串对象,s引用它,当我们说s="def"时,另一个字符串对象"def"被创建并由s引用,因此放弃了"abc"。
所以"abc"留在堆中,现在假设这是一些高度安全的密码漂浮在堆中,只等着被某个错误方访问。
这就是为什么建议使用char[]作为密码的原因。
还有其他替代方案,比如StringBuffer。

但是,除非你够愚蠢,还把它作为实习生,否则一个字符串和一个数组一样快地被GCed了。(事实上,一个字符串就是一个数组,只不过多了一些额外的字段。) - Hot Licks
Java 1.8.20引入了字符串去重功能,可以自动将字符串进行内部化处理,而无需手动操作。 - Ryan
1
@Ryan 字符串去重,顾名思义,仅在您有重复字符串时才相关,换句话说,不仅存在一个现有字符串,而且至少存在两个。对于即将被垃圾回收的字符串没有任何关联。 - Holger
1
@HotLicks 实际上,无论你是否在其上调用 intern(),它都会像普通数组一样被垃圾回收。但是,在任何情况下,被回收并不意味着其内存被覆盖。当然,将 "password" 写入代码中是另一回事,因为字符数据甚至在没有创建字符串时就存在于类数据的一部分中。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接