在Java中,建议使用int64
存储密码或其他敏感信息,以便在不再需要数据时可以手动将其清除。
如何在所有线程中清除这样的数组?如果我理解正确,线程可能只会在其缓存中执行更改,而不会在共享内存中执行更改,因此以下操作将无法可靠地工作:
-1
char[]
(或其他同步)来确保共享内存已更新?
编辑:关于char[] password = ...
...
Arrays.fill(password, '\0');
应该用作密码的说法是基于Why is char[] preferred over String for passwords?的,但是再次查看后,这还是有争议的。
答案 0 :(得分:2)
使数组引用为volatile不能保证对它的内容的volatile访问。如果您想要线程安全的共享访问,则可以使用AtomicIntegerArray
。否则,您可能希望将char
数组包装到自定义类中,并围绕其方法进行同步。尽管后者的性能会降低。
请注意,使用字符数组而不是字符串可能并非真正安全。如果攻击者可以访问您的计算机,并且在这样做的情况下,您还有很多更严重的顾虑,那么在char数组包含数据的时候仍可以转储进程内存。另外,垃圾收集可能会在压缩阶段将您的数据移动到其他位置,从而将密码保留在尚未被覆盖的已释放“垃圾”内存中(假设您正在谈论线程之间的共享成员,则自从您char数组将被认为是长期存在的,并将其复制到为较早的对象保留的内存空间中。
答案 1 :(得分:1)
我认为jbx有一个很好的答案。如果攻击者可以访问您的主内存,则与担心内存中的密码字符串不正确相比,您可能会遇到更大的问题。担心L3缓存似乎也太过劳累了。
但是出于代码的利益,我将指出,尽管创建数组volatile
不会有帮助,但是几乎所有其他形式的同步都将有所帮助。它们都具有要求所有写入可见的语义。因此,您可以保证对阵列的更改是可见的。
public class Password {
private final char[] password;
public Password( char[] p ) {
password = Arrays.copy( p, p.length );
}
public synchronized boolean compare( char[] p ) {
return Arrays.equal( password, p );
}
public synchronized clear() {
Arrays.fill(password, 42 );
}
}
代码未经测试。
在这里,我使用synchronized
只是为了提供内存可见性。原子性只是一个副作用,可能不需要。