当前位置: 首页 > 知识库问答 >
问题:

通过在垃圾收集之前使用反射清除内容,安全地使用字符串作为密码

应俭
2023-03-14

使用反射擦洗String是否使使用String与使用char[]作为密码一样安全?

从安全性方面来看,通常认为使用char[]存储/传递密码是最佳做法,因为可以在代码中尽快将其内容归零,这可能在垃圾收集清理和重新使用内存(清除所有跟踪)之前就已经很明显了,从而限制了内存攻击的时间窗口。

然而,char[]不如String方便,因此如果需要,可以“擦洗”String,从而使Stringchar[]一样安全,这将非常方便。

下面是一个使用反射将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/忽略它们),也不会重构重复的代码。

共有2个答案

公西姚石
2023-03-14

我反对字符串的一个论点是,无意中复制字符串太容易了。理论上安全使用字符串是可能的,但是整个库生态系统是基于复制字符串完全可以的假设。最后,考虑到所有的限制,字符串在这个用例中可能不像通常那样方便。

钱青青
2023-03-14

有两个潜在的安全问题:

>

  • 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 无效。 (假设池中仅存在一组特定的文本,它们永远不会过时,迟早会再次需要它们)