使用反射擦洗String
是否使使用String
与使用char[]
作为密码一样安全?
从安全性方面来看,通常认为使用char[]
存储/传递密码是最佳做法,因为可以在代码中尽快将其内容归零,这可能在垃圾收集清理和重新使用内存(清除所有跟踪)之前就已经很明显了,从而限制了内存攻击的时间窗口。
然而,char[]
不如String
方便,因此如果需要,可以“擦洗”String
,从而使String
与char[]
一样安全,这将非常方便。
下面是一个使用反射将String
字段归零的方法。
这种方法“正常”吗?它是否实现了使字符串
与密码的字符【】
一样安全的目标?
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
常量,因此调用此方法不会对插入的String产生不利影响。
此外,为了简单起见,我认为该方法是一种相当“原始”的状态。如果我使用它,我不会声明抛出的异常(try/catch/忽略它们),也不会重构重复的代码。
我反对字符串的一个论点是,无意中复制字符串太容易了。理论上安全使用字符串是可能的,但是整个库生态系统是基于复制字符串完全可以的假设。最后,考虑到所有的限制,字符串在这个用例中可能不像通常那样方便。
有两个潜在的安全问题:
>
String可能与其他String共享它的后备数组;例如,如果String
是通过在更大的String
上调用substring
创建的。因此,当整个value
数组为零时,可能会覆盖其他不包含密码的字符串的状态。
解决方法是只将密码字符串使用的支持数组部分归零。
JLS(17.5.3)警告说,使用反射来更改最终变量的影响尚未定义。
然而,这里的上下文是Java内存模型,以及允许编译器积极缓存
final
变量这一事实。在这种情况下:
>
您会期望String是线程受限的,并且
你不应该再使用这些变量了。
我不认为这两个是真正的问题...模数修复
value
的过度侵略性归零。
但真正令人担忧的是迅猛龙。:-)
我很困惑,你会真的费心去像这样清除密码。当你想到这一点时,你要防范的是有人可以读取进程内存...或者核心转储或交换文件...来检索密码的可能性。但是如果有人能做到这一点,你的系统安全肯定已经受到威胁了... cos的这些东西很可能需要
root
访问权限(或等效的权限)。如果他们有root
访问权限,他们可以“调试”你的程序,并在你的应用程序清除密码之前捕获密码。
这是一个内存数据安全问题。 java垃圾收集是否安全地清除垃圾数据? 显然,在一个数据块被垃圾收集后,我不能再检索它了,但黑客还能通过内存转储来检索数据吗?
问题内容: 与同事进行了讨论。当诸如c#或java垃圾之类的语言收集诸如字符串之类的对象并将其返回到堆时,它们是否也清除了该内存块,例如用0或1覆盖? 我的假设是,除非按原样返回该块,除非使用诸如带有带有finalize重载的securestring之类的类将该块清零。 问题答案: 实际上,不,这不会发生。覆盖刚刚释放的内存需要花费时间,因此会有性能损失。“安全”之类的物体SecureString
问题内容: 我正在阅读有关垃圾收集的信息,当我搜索字符串文字垃圾收集时,搜索结果令人困惑。 我需要澄清以下几点: 如果在编译时将字符串定义为文字字符串,那么是否会对其进行垃圾回收? 如果使用实习方法,那么它会被垃圾回收吗?在第1点中,它也将与文字区别对待。 有人提到只有在卸载类时才会对文字进行垃圾回收吗?是否有道理,因为我认为永远不会卸课。 问题答案: 如果在编译时将字符串定义为文字字符串,那么是
问题内容: Go是一种垃圾回收语言: http://golang.org/doc/go_faq.html#garbage_collection 在这里,它说这是一个标志性的垃圾回收器,但是它没有深入研究细节,并且正在进行替代…但是,自Go发行以来,该段似乎没有太多更新。 它仍然是标记和扫描?是保守还是精确?它是世代相传的吗? 问题答案: Go 1.4+垃圾收集器的计划: 混合世界/并发收集器 截止
问题内容: 我想向JVM注册一个回调,所以我知道何时进行垃圾回收。有什么办法吗? 编辑:我想这样做,以便可以在应用程序日志中发生垃圾收集时注销,这样我就可以查看它是否与我所看到的问题相关。启用- Xloggc很有帮助,但是将GC日志中的时间(自应用程序启动以来使用秒数)整合到我的主应用程序日志中有点棘手。 编辑2012年4月:从Java7u4开始,您可以从GarbageCollectorMXBea
我在网站上读到了这个问题:java内存池是如何划分的?我想知道“字符串常量池”属于这些扇区中的哪一个? 还有池中的文字是否曾经被 GC 化? 方法从池中返回文字的基链接。 如果池确实被 GC 处理,那么它不会对字符串池的想法适得其反吗?将再次创建新的文本,使 GC 无效。 (假设池中仅存在一组特定的文本,它们永远不会过时,迟早会再次需要它们)