通过在垃圾回收之前使用反射来清理内容,安全地使用 String 作为密码
使用反射来擦除是否与使用密码一样安全?String
String
char[]
从安全方面来看,通常用于存储/传递密码被认为是最佳实践,因为人们可以在代码中尽快将其内容清零,这可能在垃圾回收清理它并重用内存(擦除所有痕迹)之前,限制了内存攻击的时间窗口。char[]
但是,并不像 ,所以如果需要,如果可以“擦洗”一个,那就很方便了,从而像 .char[]
String
String
String
char[]
下面是一个使用反射将 的字段清零的方法。String
此方法是否“OK”,它是否实现了与密码一样安全的目标?String
char[]
public static void scrub(String str) throws NoSuchFieldException, IllegalAccessException {
Field valueField = String.class.getDeclaredField("value");
Field offsetField = String.class.getDeclaredField("offset");
Field countField = String.class.getDeclaredField("count");
Field hashField = String.class.getDeclaredField("hash");
valueField.setAccessible(true);
offsetField.setAccessible(true);
countField.setAccessible(true);
hashField.setAccessible(true);
char[] value = (char[]) valueField.get(str);
// overwrite the relevant array contents with null chars
Arrays.fill(value, offsetField.getInt(str), countField.getInt(str), '\0');
countField.set(str, 0); // scrub password length too
hashField.set(str, 0); // the hash could be used to crack a password
valueField.setAccessible(false);
offsetField.setAccessible(false);
countField.setAccessible(false);
hashField.setAccessible(false);
}
这是一个简单的测试:
String str = "password";
scrub(str);
System.out.println('"' + str + '"');
输出:
""
注意:您可能认为密码不是常量,因此调用此方法不会对传入字符串产生不利影响。String
另外,为了简单起见,我离开了这个方法,这是一个相当“原始”的状态。如果我使用它,我不会声明抛出的异常(尝试/捕获/忽略它们)并重构重复的代码。