Java敏感数据:char[]还是String?有什么区别?

6
我们已经知道使用char[]替代String来处理敏感数据的建议/实践。这样做有多个原因。其中之一是在敏感数据不再需要时立即清除它们:
char[] passwd = passwordProvider.getKeyStorePassword();
KeyStore keystore = KeyStore.getInstance("JKS");

// TODO: Create the input stream;
keystore.load(inputstream, passwd);

System.arraycopy(new char[passwd.length], 0, passwd, 0, passwd.length);

// Please continue...

现在的问题是:当敏感数据最初以String值的形式传递给您时,使用char[]是否有意义(特别是上面提到的点)?例如:
char[] passwd = passwordProvider.getKeyStorePassword().toCharArray();
KeyStore keystore = KeyStore.getInstance("JKS");

// TODO: using the passwd, load the keystore;

System.arraycopy(new char[passwd.length], 0, passwd, 0, passwd.length);

// Please continue...

提前感谢您。

更新2:我会重新表述问题:在这个特定的上下文中(忘记未来的变化或其他任何事情),“清除char数组的内容”这行代码有任何好处吗?

更新1:这不是为什么密码首选char[]而不是String?的复制。 我知道故事是什么。 我问的是在这种特定的情况下,它是否仍然有意义?


2
可能是为什么char[]比String更适合用于密码?的重复问题。 - log N
我认为这有一定道理。拥有更多的安全屏障是更好的选择。此外,这将确保如果您切换到不同的密码提供者,您不必更改代码。 - yeputons
你说得对。但是我想知道在这个特定的情境下是否有意义,答案是否定的,没有太多意义。 - Rad
1
顺便提一下,Arrays.fill(passwd, '\0') 是清空数组更好的方法,因为它避免了创建新数组。 - Andy Turner
1个回答

6

在我看来,密码提供程序API的设计存在安全问题,因为它返回一个String

但是,如果你必须使用该API,立即转换为char[]意味着你不会防止String实例被垃圾回收,因为你不会长时间持有对它的引用,仅仅需要尽可能短的时间。

因此,在这里使用char[]是有意义的,因为你“并没有使情况更糟”。


我们接近我想学习的内容了:立即转换为char[]。如果我先将getKeyStorePassword方法的结果存储在一个String变量中,然后再将其转换为char[],这会在低级别上改变任何东西吗?据我所知,这不应该有任何区别。是这样吗?(假设任何地方任何时候都不允许进行更改) - Rad
@Rad调用a.b().c()会将a.b()的结果存储在堆栈上,然后在其上调用c()。这基本上与将其放入变量中相同。关键是,如果您有一个显式变量包含该中间结果,您可以故意或无意中对其进行染污。您可以勤奋地仔细审查代码以确保不会发生这种情况,或者根本不创建变量,从而不允许泄漏发生。 - Andy Turner
当然,在你将其清零之前,没有什么阻止你从char[]构建另一个String... - Andy Turner
明白了,谢谢。只是想澄清一下:...将a.b()的结果存储在堆栈上。我认为你的意思是将结果的引用(由于它不是原始类型,所以在堆中)存储在堆栈中。对吗? - Rad
顺便说一下,如果你能确定该字符串不是共享的,那么你可以破坏该字符串的char[],这只是一种hacky的方法,但你可以这样做。如果它是共享的,那么你就有了一个不同的问题,即该字符串被保留/缓存在某个地方。 - Peter Lawrey
显示剩余3条评论

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