Securing a symmetric encryption key in memory
我有一个应用程序,我正在检索磁盘中存在的对称加密密钥并使用它来加密数据。程序启动时从磁盘中检索加密密钥,并将其作为字节数组存储在私有类变量中。在程序启动时从磁盘中检索到密钥后,在密钥上使用
让我思考这个方案的有效性的部分是在从磁盘检索密钥的情况下,并且每次需要将密钥用作易于利用的漏洞时,都会在 2 个关键时刻创建程序的执行周期:当程序刚刚完成从磁盘加载密钥并且没有调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class ApplicationClass { private byte[] encKey; public ApplicationClass() { // Fetches the encryption key first encKey = StorageInt.FetchKey(); // Fetches and returns the encrypted key from the disk // A gaping vulnerability here as the key is just loaded in memory and is not protected ProtectedMemory.Protect(encKey, MemoryProtectionScope.SameProcess); // Other initialization instructions follows } private byte[] ApplySymmEnc(byte[] plaintext) { Aes aes = Aes.Create(); byte[] iv = new byte[128]; RNGCryptoServiceProvider randomBytesGenerator = new RNGCryptoServiceProvider(); randomBytesGenerator.GetNonZeroBytes(iv); randomBytesGenerator.Dispose(); ProtectedMemory.Unprotect(encKey, MemoryProtectionScope.SameProcess); // Another gaping vulnerability here! ICryptoTransform encryptor = aes.CreateEncryptor(encKey, iv); ProtectedMemory.Protect(encKey, MemoryProtectionScope.SameProcess); // Protect the key right after it is used for encryption // Instructions for encryption follows } } |
提前致谢。
编辑:至于在磁盘上不关心密钥安全性的原因,密钥以相当安全的模糊形式存在于磁盘中,在检索时由
防御所有攻击是不可能的。您可以获得的最接近的可能是使用可信平台模块 (tpm) 芯片,因此密钥永远不会离开芯片。如果您的处理器提供了可信的执行环境,那么第二好的可能是使用可信的执行环境。但两者都无法抵御各种攻击。
如果没有专门的硬件支持,尝试保护您的程序免受管理员的侵害可能是不可行的。如果攻击者可以读取你程序的内存,为什么他不能直接从磁盘读取密钥呢?
在 ram 中加密密钥对于防止诸如冷启动攻击之类的攻击很有用,而此类攻击可能很难在易受攻击的时刻正确获取密钥。
在内存中键的最佳实践问题中也有一些可能有用的答案。
在这些时间(从磁盘获取之后但在调用 ProtectedMemory.Protect 之前)保持对称加密密钥的保护需要操作系统级别的支持,这在 Windows(和其他 .net 核心平台)中不存在。
直接来自 .net 团队关于处理凭据的类似主题:"SecureString 的目的是避免将机密作为纯文本存储在进程内存中。......但是,即使在 Windows 上,SecureString 也不会\\' t 作为操作系统概念存在...它只是使获取纯文本的窗口更短...处理凭据的一般方法是避免使用它们,而是依靠其他方式进行身份验证,例如证书或 Windows 身份验证" (https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md)
你提到了
"when the program has just finished loading the key from the disk and
has not called theProtect() "
如果我改写上面的句子
你可以为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public int StorageInt.FetchKey(bool IsProtectKey = true) { encKey = StorageInt.FetchKey(); CodeEncryptedKey = EncryptAndStoreProtectedKey(); //Above function should encrypt your"encKey" to AES256 or to any secure encryption algorithm, store it in cache and return encrypted key ProtectedMemory.Protect(encKey, MemoryProtectionScope.SameProcess); } Public string UseKey(string CodeEncryptedKey) { encKey = GetProtectedKeyFromCache(CodeEncryptedKey) ProtectedMemory.Unprotect(encKey, MemoryProtectionScope.SameProcess); Task.Run(() => ProtectKeyAfter5Seconds(encKey)); return encKey; } Void ProtectKeyAfter5Seconds(encKey) { Thread.Sleep(5000); //Im telling here to encrypt after 5 seconds, you can have your logic to encrypt after one time use or any particular logic ProtectedMemory.Protect(encKey, MemoryProtectionScope.SameProcess); } |
这有帮助吗?