【发布时间】:2021-04-04 17:02:47
【问题描述】:
我浏览了 Cure53 审计,发现在 pg 中提到了“安全密钥删除无效(中)”。 3here。 Cure53 团队说没有真正的方法可以使用 Go 擦除内存中的敏感数据。
有没有办法在 C# 中做到这一点? C# 在这方面也受到垃圾收集的限制,但肯定有一些方法可以擦除字节数组等。
【问题讨论】:
标签: encryption .net
我浏览了 Cure53 审计,发现在 pg 中提到了“安全密钥删除无效(中)”。 3here。 Cure53 团队说没有真正的方法可以使用 Go 擦除内存中的敏感数据。
有没有办法在 C# 中做到这一点? C# 在这方面也受到垃圾收集的限制,但肯定有一些方法可以擦除字节数组等。
【问题讨论】:
标签: encryption .net
问题不在于擦除字节数组。您可以擦除字节数组。例如,问题是 .NET 的 GC 可能在碎片整理阶段移动了字节数组,因此内存中某处存在数组的幻像副本。你可以通过固定数组来解决这个问题,这样它就不会被 GC 移动。这可以解决
但是,用于实现密钥擦除的策略可能无效,因为 Go 的基于垃圾收集的内存管理模型的局限性1
但它不会解决
此外,它不会尝试定位残差值,例如中间值 计算,因此可能会保留在内存中。
当您进行公钥加密时,您必须进行许多大数数学运算。中间结果在某处。安全编写的库应该像处理初始值一样安全地处理所有这些中间结果(对称加密通常更容易:通用算法可以直接在将用于输出的缓冲区中工作)。但是你必须以这种方式编写库:-)
所有这些东西并不能真正保护你。如果外部进程可以访问您的进程的内存,它可以不断检查直到找到密钥......之前或之后,您的密钥将在内存中未加密。由于这个原因,.NET SecureString 不是最终解决方案:https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
它只是使纯文本的窗口更短;它并没有完全阻止它,因为 .NET 仍然必须将字符串转换为纯文本表示形式。
真正的解决方案必须存在于操作系统级别,甚至更好地存在于操作系统加处理器级别。受保护的内存只能由单个进程读取,或者更好的是只写,所有加密都在操作系统/处理器级别完成(否则木马可以将自己注入您的进程)
最后,唯一真正好的解决方案可能是Hardware Security Module:
硬件安全模块 (HSM) 是一种物理计算设备,用于保护和管理数字密钥、执行数字签名的加密和解密功能、强身份验证和其他加密功能。这些模块传统上以插入卡或直接连接到计算机或网络服务器的外部设备的形式出现。
但是,我们超出了“如何安全地对我的应用程序或库进行编程”的范围。我们正在解决问题。
【讨论】:
GCHandle gc = GCHandle.Alloc(yourByteArray, GCHandleType.Pinned)。记得取消固定,否则会一直固定!所以做一个try { pin(bytearray); do_work() } finally { unpin } 或实现一个IDisposable + destructor 模式(GCHandle 就像一个非托管资源)。最好的方法是将字节数组封装在实现完整的IDisposable + destructor 模式的class PinnedByteArray : IDisposable 中,并且在 Dispose() 中使用 0x00 清除数组......我应该在某处有一些代码......我'来看看
与其将加密密钥加载到内存中并在使用后尝试将其擦除,不如考虑根本不将密钥加载到内存中。
在 Windows 上,您可以通过使用 CNG key store provider 存储密钥并使用 CNG 执行所有加密操作来实现此目的。与 CryptoNG(以及许多其他加密库)不同,CNG offloads crytographic operations to LSASS 甚至不会将密钥加载到进程的内存中。
.NET 库中的大多数加密类都有 CNG 和 CryptoAPI 变体,例如 RSACng (CNG) 和 RSACryptoServiceProvider (CryptoAPI)。
【讨论】: