Java安全性:如何清除/清零与对象相关的内存?(和/或确保这是特定变量的唯一实例/副本)
我正在讨论如何保护存储在Java程序中的敏感信息(例如密码)。根据安全要求,清除包含敏感信息的内存,例如,通过将字节值设置为所有零。令人担忧的是,攻击者可以观察与应用程序进程关联的内存,因此我们希望尽可能限制此类敏感信息挂起的时间窗口。以前,项目涉及C++,因此memset()就足够了。
(顺便说一句,memset() 的使用受到了质疑,因为已知一些编译器会根据以下假设来优化其使用结果二进制文件:由于以后不会使用内存,因此无需首先将其归零。这个 blurb 是那些谷歌“memset”和“clear memory”等的人的免责声明)。
现在,我们手上有一个 Java 项目正在面临这一要求的压力。
对于 Java 对象,我的理解是:
- 空引用仅更改引用的值;对象堆上的内存仍包含数据
- 像 String 这样的不可变对象将无法修改其数据(或者至少不容易,在具有适当启用的安全管理器的 VM 范围内)
- 代际垃圾回收器可以到处复制对象(如此处所述))
对于原语,我的理解是:
- 局部方法中的基元类型变量将在堆栈上分配,并且:
- 当您更改它的值时,您可以直接在内存中修改它(而不是使用引用来处理堆上的对象)。
- 在某些情况下,可以/将复制在“幕后”制作,例如将其作为参数传递给方法或装箱(自动或不自动)创建包含另一个保持相同值的基元变量的包装器实例。
我的同事声称Java原语是不可变的,并且NSA和Oracle都有关于Java缺乏对此要求的支持的文档。
我的立场是,基元可以(至少在某些情况下)通过将值设置为零(或布尔值设置为false)来归零,并且以这种方式清除内存。
我试图验证JLS或其他“官方”文档中是否有关于JVM在内存管理方面与原语相关的所需行为的语言。我能找到的最接近的是Oracle网站上的“Java编程语言安全编码指南”,其中提到使用后清除char数组。
当我的同事称原语不可变时,我会对定义提出质疑,但我非常确定他的意思是“内存不能被适当地归零” - 让我们不要担心这一点。我们没有讨论他是否意味着最终变量 - 从上下文中我们一般地谈论。
对此是否有任何明确的答案或参考?我很感激任何能告诉我哪里错了或确认我是对的东西。
编辑:经过进一步的讨论,我已经能够澄清我的同事正在考虑原始包装器,而不是原始包装本身。因此,我们留下了如何安全地清除内存的原始问题,最好是清除对象的内存。另外,为了澄清,敏感信息不仅仅是密码,还包括IP地址或加密密钥等内容。
是否有任何商业JVM提供诸如优先级处理某些对象之类的功能?(我想这实际上会违反Java规范,但我想我会问,以防万一我错了。