我知道为了删除一个 Java 对象,我应该使用字符数组而不是字符串,因为我可以安全地擦除(用其他数据重写字符数组)它的内容。这对于 String 对象似乎是不可行的。
现在在基于 Java 的 BlackBerry 上,我无法找到将数据作为字符数组处理的 API,但我不得不使用 String。因此我的问题是,如果我将密码存储在对象中,如何安全地删除它?
我知道为了删除一个 Java 对象,我应该使用字符数组而不是字符串,因为我可以安全地擦除(用其他数据重写字符数组)它的内容。这对于 String 对象似乎是不可行的。
现在在基于 Java 的 BlackBerry 上,我无法找到将数据作为字符数组处理的 API,但我不得不使用 String。因此我的问题是,如果我将密码存储在对象中,如何安全地删除它?
实际上,您不能真正“安全地擦除”Java 中的字符数组。Java 通过垃圾收集器进行内存分配,这是一个棘手的软件,在实践中,它会定期将内存对象移动到物理 RAM 中。所以你认为的“一个char[]
实例”将被复制到几个地方,而擦除只会在其中一个地方发生。
在这种情况下,“安全删除”在 Java 中不可能真正存在。如果您使用 Java,则必须确保使用上下文使得安全删除是不必要的:当操作系统可能分配非零化 RAM 块时(因此应用程序可能会从其他应用程序获取旧 RAM 的摘录),通常需要“安全删除” ),或者存在虚拟内存(RAM 的一部分被复制到硬盘)。我想这些不适用于黑莓,所以简单的String
实例应该没问题。
另一种说法是,如果String
实例不适合密码,那么您会遇到比单纯的密码泄漏更大的安全问题。毕竟,您使用密码来保护对某些数据的访问,因此如果您需要对密码进行“安全擦除”,那么从逻辑上讲,您还需要对受保护数据以及您所做的一切进行“安全擦除”用它。
(可以猜到我不是“安全擦除”概念的忠实拥护者。)
如果我将密码存储在对象中,如何安全地删除它?
我想你的意思是;如何防止有权访问设备的攻击者恢复密码?
这取决于攻击者获得的访问级别。
如果攻击者仅限于您提供的外部 API(不是一个好的假设),那么使用 java.security.AccessController 进行访问控制就足够了。如果您正确设计了访问控制(很难做到)并且攻击者无法绕过访问控制,那么访问控制将阻止攻击者获取数据。
如果攻击者仅限于在 Java 虚拟机中操作而不是在您的 API 中操作,则您需要使用 KeyStore.PrivateKeyEntry 保护数据。在这个级别上,您不能依靠设计的正确操作来保护数据,而必须依靠 Java 虚拟机来提供保护。
如果攻击者仅限于操作系统(而不是 Java 虚拟机),那么您将无法保护您的数据。如果攻击者可以阻止 Java 虚拟机按设计运行,那么攻击者可以绕过任何 Java 安全机制。
如果攻击者可以物理访问设备,就不可能保护数据免受所有攻击。在这个级别,攻击者可以在将数据写入 RAM、闪存、硬件模块等时读取数据。
你说得对。正如您所指出的,对象(例如不可变字符串)的生命周期由垃圾收集器管理。因此,如果敏感信息在字符串中,则无法覆盖敏感数据。此外,数组的生命周期由垃圾收集器管理,但您可以覆盖内容,因此如果您用随机数据(或零)覆盖内容,您将“删除”内容。
查看 BlackBerry 站点 [1],实际上他们的 JVM 似乎支持 char[] 数组。如果 - 出于不清楚的原因 - BlackBerry JVM 不提供此基本结构,则应将机密位存储在 byte[] 数组中,然后使用该数组覆盖该数组。
如果我们不尝试删除它,而是用无意义的值覆盖它,那就更容易了。甚至 string.value 也可以被无用的字符集覆盖。