我有一个代码,我想知道是否可以阻止 JIT 优化方法clearArraySafely? 是否可以有选择地禁用某些代码部分的 JIT?
或者我如何确定这段代码不会被优化?
private static char[] password;
public static void clearArraySafely() {
// Overwritting array
for (int i = 0 ; i <= password.length; i++) {
password[i] = 0;
//System.out.print(i); // <- I don't want to do this trick to be sure
}
password = null;
}
有什么好的类来存储由字符数组组成的密码吗?
这个问题有两个答案:
据我所知,没有办法在不关闭所有方法的情况下“关闭”方法的优化。
您可以做一些可能会抑制您担心的当前一代 Java 编译器的特定优化的事情。 例如:
private static char[] password;
public static String dummy;
public static void clearArraySafely() {
// Overwritting array
for (int i = 0 ; i <= password.length; i++) {
password[i] = 0;
}
dummy = new String(password);
password = null;
}
JIT 编译器无法优化掉零赋值。 如果是这样,那么将使用“错误”的内容创建虚拟字符串。 由于
dummy
可以通过反射访问而不违反任何 JLS 规则,因此 JIT 无法应用转义分析来避免创建它。
但请注意,未来一代 JIT 编译器总有可能变得……更聪明。 如果你想避免这种情况,你需要确保
dummy
以某种方式影响程序的输出;例如通过打印它。有什么好的类来存储由字符数组组成的密码吗?
据我所知,没有人不会遇到同样的问题。
话虽如此,达到这个级别来保护密码(在我看来)近乎偏执。 如果某人具有从堆中无法访问的对象中窃取密码所需的访问级别,他们很可能可以通过其他方式获取密码;例如通过在操作系统级别拦截字符,或者通过“调试”您的 JVM。
我的偏执与调试 JVM 有关。
不幸的是,你的偏执无济于事。
例如,您设计的用于防止某人附加调试器的方案可以通过逆向工程然后修改
exe
文件来破坏。 您设计的任何其他方案也可以。
如果用户控制了程序执行的平台,则无法阻止他/她“调试”正在运行的程序。 防止这种情况的唯一方法是仅在您控制的平台上运行应用程序。
(顺便说一句 - 这不是 Java 特有的问题。它适用于所有编程语言。有些语言比其他语言更容易“破解”,但如果不道德的用户技术熟练、积极主动且有时间,那么它们“所有”都可以被破解开发“黑客”。)
password
是对数组的引用,而不是实际的数组。考虑一下:
char[] passwordCopy = password;
clearArraySafely();
// do something with passwordCopy
如果编译器删除归零,此代码将中断。如果 Java 使用引用计数,那么我想如果它看到引用计数为 1,它可以“优化”它,但这似乎不值得做。大多数时候,人们编写代码并不是为了改变随后被丢弃的东西。
您可能还想考虑使用
GuardedString
。