如何确保在Java中销毁String对象?

zne*_*eak 38 java security

我公司的员工需要通过我制作的程序修改SQL Server数据库中的数据.该程序首先使用Windows身份验证,我要求DBA为此特定用户提供对所述数据库的写访问权限.

他们不愿意这样做,而是给我的 Windows用户帐户提供写访问权限.

因为我相信这个人但是还不足以让他在我的会话打开的情况下工作90分钟,我只会在我的程序中添加一个登录提示,要求输入用户名和密码,然后使用它登录到SQL Server.我会登录,并相信我的应用程序让他只做他需要的东西.

然而,这会带来很小的安全风险.该密码字段教程太阳 Oracle的网站指出,密码应保持在内存中所需要的最短时间,并为此目的,该getPassword方法返回一个char[]数组,一旦你用它做,你可以零.

但是,Java的DriverManager类只接受String对象作为密码,所以一旦我完成它,我将无法处理密码.而且由于我的应用程序在分配和内存要求方面非常低,谁知道它能在内存中存活多久?如上所述,该程序将运行相当长的时间.

当然,我无法控制任何的SQL Server的JDBC类与我的密码,但我希望我能控制什么做我的密码.

有没有一种可靠的方法来破坏/清除StringJava对象?我知道两者都有点违背语言(对象破坏是非确定性的,String对象是不可变的),并且System.gc()有点不可预测,但仍然存在; 任何的想法?

jta*_*orn 21

所以,这是坏消息.我很惊讶没人提到它.与现代垃圾收集器,甚至整个char []概念被打破.无论你是使用String还是char [],数据最终都会存在于内存中,以便知道多长时间.这是为什么?因为现代的jvms使用世代垃圾收集器,简而言之就是在整个地方复制对象.所以,即使你使用了char [],它使用的实际内存也可以被复制到堆中的各个位置,在任何地方都会留下密码的副本(并且没有高性能的gc会将旧内存清零).所以,当你将最后的实例归零时,你只是将内存中的最新版本归零.

长话,简而言之,没有防弹方式来处理它.你几乎要相信这个人.

  • @meriton - 我记得有一篇文章详细介绍了一些与此相关的测试,但是我最后一次看不到它.至于清零内存,并非​​所有内存使用都是新的对象分配.例如,当现有对象从一代复制到另一代时,不需要事先将目标清零. (3认同)

Mar*_*ers 11

我只能想到使用反射的解决方案.您可以使用反射来调用使用共享字符数组的私有构造函数:

  char[] chars = {'a', 'b', 'c'};
  Constructor<String> con = String.class.getDeclaredConstructor(int.class, int.class, char[].class);
  con.setAccessible(true);
  String password = con.newInstance(0, chars.length, chars);
  System.out.println(password);

  //erase it
  Arrays.fill(chars, '\0');
  System.out.println(password);
Run Code Online (Sandbox Code Playgroud)

编辑

对于任何认为这是一个防故障甚至有用的预防措施的人,我鼓励你阅读jtahlborn的答案,至少有一个警告.


nec*_*cer 5

如果绝对必要,请保留对字符串的 WeakReference,并继续吞噬内存,直到强制对字符串进行垃圾回收,您可以通过测试弱引用是否已变为 null 来检测。这可能仍然将字节留在进程地址空间中。垃圾收集器再搅动几次可能会给您带来安慰吗?因此,在原始字符串弱引用被清空后,创建另一个弱引用并搅动直到它被清零,这意味着完整的垃圾收集周期已完成。

不知何故,我必须添加哈哈,即使我上面的回答是完全严肃的:)