使用反射来擦除字符串(String
)是否能让使用字符串与使用char[]
一样安全?
从安全角度考虑,通常最好使用char[]
存储/传递密码,因为可以在代码中尽早将其内容清零,这可能会比垃圾回收清理并重复使用内存(擦除所有痕迹)的时间要短得多,从而缩短了进行内存攻击的窗口。
但是,char[]
不如String
方便,因此如果需要的话,将String
“擦洗”一下可能很方便,从而使String
与char[]
一样安全。
下面是一种使用反射来清空String
字段的方法。
这个方法“可以”,并且是否实现了使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
常量,因此调用此方法不会对内部化字符串产生不利影响。
另外,出于简单起见,我将该方法保留在相当“原始”的状态。如果我要使用它,我将不会声明抛出的异常(try/catch/忽略它们)并重构重复的代码。
String
实现不会有偏移量。你应该更加健壮(这在大多数反射代码中并不常见)。“内存窥探”并不是完全不切实际的攻击,特别是当你考虑到交换/休眠可能会将数据放置在物理介质上很长一段时间时。 - Tom Hawtin - tackline