如何 "zero out" 并确保从内存中删除字符串
How to "zero out" and ensure deletion of a string from memory
我了解垃圾回收的主要概念,即一旦某个特定对象没有更多指针引用它,它就是 "garbage collected"。
这是否意味着它已被释放但它的价值仍然可供具有 debugger/disassembler 的人阅读(至少在该地址被写入之前)?
我知道对于大多数对象(那些在 C#
中实现 IDisposable
接口的对象,您可以调用 Dispose()
方法并且非常有信心永远不会再次访问内存。但是呢字符串?
我知道垃圾回收(在 iOS 中它被称为 ARC
)一旦你达到 0 引用对象 "disposes" 本身。我担心我的应用程序(我接手的大量遗留代码)有大量内存泄漏和强引用,我不希望 PCI 敏感数据 在我很久之后仍然存在于内存中已经 "set the String
to null
"。将字符串设置为 null 是否为字符串中的每个字符放置一个 null 终止字符?
这是我迄今为止所做的一些研究的一些链接,我想也许我正在寻找的可能是 writing/re-writing 在我完成非托管内存之后:
TLDR:
我知道我可以将 String
设置为 null
但我仍然不相信我的应用程序没有内存中仍然可以引用的敏感数据被恶意的一方。
你如何保证(希望通过 code/unit 测试)一个字符串永远不会从内存中再次引用(即使来自恶意的第 3 方)。
抱歉,如果我有点偏执,我刚刚在这个代码库中看到了如此糟糕的内存管理(大部分来自深度嵌入的第三方框架)。
I understand the main concept of garbage collection, about how once a
specific object has no more pointers referencing it, it is "garbage
collected".
差不多。要点是,在对该对象的最后一次引用被销毁后,该对象不会立即被垃圾回收。在该对象处于挂起状态并等待启动垃圾收集过程之后。
Does this mean it is freed up but it's value is still available for
someone with a debugger/disassembler to read (at least until that
address is written to)?
是的。正如我上面提到的,释放的对象仍在内存中等待 GC 启动。因为垃圾收集是不确定的,所以您无法准确知道垃圾收集器何时执行其工作。
而且,你仍然可以获得这个对象的引用(通过Finalize方法Finalize override docs link)
I know with most objects (those implementing IDisposable interface in
C# you can call the Dispose() method and be pretty confident that
memory can never be accessed again. But what about strings?
此接口的主要用途是释放非托管资源。当不再使用该对象时,垃圾收集器会自动释放分配给该对象的内存。
Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector.
处理一个托管对象并不意味着这个对象被释放——Dispose 只改变这个对象的内部状态(例如它释放原生位图引用),但对象保持不变——它消耗内存,它仍然可以使用,你可以调用它的方法等。只有GC从内存中删除一个对象。
因此,字符串作为托管对象,由GC释放。
How do you guarantee (from code/unit tests hopefully) a string cannot
EVER be referenced again from memory (even from a malicious 3rd
party).
IMO,解决方案是使用类似处置的功能实现您自己的字符串包装器 - 例如,在您使用此包装器的实例 class 并且不再需要它后,您可以调用 Free( ) 方法和您的实现将重写内存中底层字符串的值(在安全或不安全的上下文中)。但它需要准确的资源管理。此外,应通过 Finalize() 方法调用字符串重写,以确保对象被 GC 后内存归零。
接受@barac340 的回答,因为它对于帮助我理解内存管理以找到我的解决方案至关重要。
- 我只使用
SecureString
,用一个方法同时发送
它通过加密通道出来,然后删除 SecureString
已通过。
- 我使用
Marshal
class 重写每个空字符
byte 为 SecureString
从内存地址开始的字节长度
非托管内存中的 SecureString
。
- 然后我处理掉它,释放出一堆空字符用于
垃圾收集。 :)
我确实想澄清一下,Xamarin.iOS 上的一个已知问题是 SecureString
的内存地址未在安全字符串上加密,因此即使释放内存以供 GC 使用照原样,它仍然可以通过内存检查以纯文本形式提供。
我没有创建自定义 class,不是因为它不利于重用,在这种情况下我只是在一个地方使用它。我的大多数 "future" 用例都需要在 SecureString
的实际 String
值的第一个 "get" 之后处理所述字符串。所以现在我只是将处置放在使用字符串的函数中。特别是因为我已经在使用 Marshal
来读取 String
,所以在使用相同的方法后写入它是有意义的。
如果需要自定义 class,我正在配音 "ExtraSecureString",
我会照办的。
我了解垃圾回收的主要概念,即一旦某个特定对象没有更多指针引用它,它就是 "garbage collected"。
这是否意味着它已被释放但它的价值仍然可供具有 debugger/disassembler 的人阅读(至少在该地址被写入之前)?
我知道对于大多数对象(那些在 C#
中实现 IDisposable
接口的对象,您可以调用 Dispose()
方法并且非常有信心永远不会再次访问内存。但是呢字符串?
我知道垃圾回收(在 iOS 中它被称为 ARC
)一旦你达到 0 引用对象 "disposes" 本身。我担心我的应用程序(我接手的大量遗留代码)有大量内存泄漏和强引用,我不希望 PCI 敏感数据 在我很久之后仍然存在于内存中已经 "set the String
to null
"。将字符串设置为 null 是否为字符串中的每个字符放置一个 null 终止字符?
这是我迄今为止所做的一些研究的一些链接,我想也许我正在寻找的可能是 writing/re-writing 在我完成非托管内存之后:
TLDR:
我知道我可以将
String
设置为null
但我仍然不相信我的应用程序没有内存中仍然可以引用的敏感数据被恶意的一方。你如何保证(希望通过 code/unit 测试)一个字符串永远不会从内存中再次引用(即使来自恶意的第 3 方)。
抱歉,如果我有点偏执,我刚刚在这个代码库中看到了如此糟糕的内存管理(大部分来自深度嵌入的第三方框架)。
I understand the main concept of garbage collection, about how once a specific object has no more pointers referencing it, it is "garbage collected".
差不多。要点是,在对该对象的最后一次引用被销毁后,该对象不会立即被垃圾回收。在该对象处于挂起状态并等待启动垃圾收集过程之后。
Does this mean it is freed up but it's value is still available for someone with a debugger/disassembler to read (at least until that address is written to)?
是的。正如我上面提到的,释放的对象仍在内存中等待 GC 启动。因为垃圾收集是不确定的,所以您无法准确知道垃圾收集器何时执行其工作。 而且,你仍然可以获得这个对象的引用(通过Finalize方法Finalize override docs link)
I know with most objects (those implementing IDisposable interface in C# you can call the Dispose() method and be pretty confident that memory can never be accessed again. But what about strings?
此接口的主要用途是释放非托管资源。当不再使用该对象时,垃圾收集器会自动释放分配给该对象的内存。 Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. 处理一个托管对象并不意味着这个对象被释放——Dispose 只改变这个对象的内部状态(例如它释放原生位图引用),但对象保持不变——它消耗内存,它仍然可以使用,你可以调用它的方法等。只有GC从内存中删除一个对象。 因此,字符串作为托管对象,由GC释放。
How do you guarantee (from code/unit tests hopefully) a string cannot EVER be referenced again from memory (even from a malicious 3rd party).
IMO,解决方案是使用类似处置的功能实现您自己的字符串包装器 - 例如,在您使用此包装器的实例 class 并且不再需要它后,您可以调用 Free( ) 方法和您的实现将重写内存中底层字符串的值(在安全或不安全的上下文中)。但它需要准确的资源管理。此外,应通过 Finalize() 方法调用字符串重写,以确保对象被 GC 后内存归零。
接受@barac340 的回答,因为它对于帮助我理解内存管理以找到我的解决方案至关重要。
- 我只使用
SecureString
,用一个方法同时发送 它通过加密通道出来,然后删除 SecureString 已通过。 - 我使用
Marshal
class 重写每个空字符 byte 为SecureString
从内存地址开始的字节长度 非托管内存中的SecureString
。 - 然后我处理掉它,释放出一堆空字符用于 垃圾收集。 :)
我确实想澄清一下,Xamarin.iOS 上的一个已知问题是 SecureString
的内存地址未在安全字符串上加密,因此即使释放内存以供 GC 使用照原样,它仍然可以通过内存检查以纯文本形式提供。
我没有创建自定义 class,不是因为它不利于重用,在这种情况下我只是在一个地方使用它。我的大多数 "future" 用例都需要在 SecureString
的实际 String
值的第一个 "get" 之后处理所述字符串。所以现在我只是将处置放在使用字符串的函数中。特别是因为我已经在使用 Marshal
来读取 String
,所以在使用相同的方法后写入它是有意义的。
如果需要自定义 class,我正在配音 "ExtraSecureString", 我会照办的。