我正在开发一个C ++应用程序,它将一些用户密钥保存在RAM中。这个秘密密钥非常敏感&我必须尽量减少对他们进行任何攻击的风险
我正在使用一个字符数组来存储这些键,我已经阅读了一些关于在CPU寄存器甚至CPU缓存中存储变量的内容(即使用C ++ register
关键字),但似乎没有保证的强制方法应用程序将其中的一些变量存储在RAM之外(我的意思是在CPU寄存器或缓存中)
任何人都可以建议一个好的方法来做这个或建议任何其他解决方案将这些密钥安全地保存在RAM中(我正在寻找一个独立于操作系统的解决方案)?
答案 0 :(得分:17)
你的意图可能是高尚的,但也是错误的。简短的回答是,在通用系统(即商品处理器/主板和通用O / S)上真的没办法做你想做的事。即使你可以,不知何故,强迫事情只存储在CPU上,它仍然不会真正帮助。这只会是一个小麻烦。
更一般地说,对于保护内存的问题,有一些O / S特定的解决方案来指示不应将块内存写入页面文件,例如Windows上的VirtualLock
函数。如果您正在进行加密并将敏感数据保存在该内存中,那么这些值得使用。
最后一件事:我要指出的是,我担心的是你对register
关键字及其安全隐患有一个根本的误解;记住它是一个暗示,它不会 - 实际上,不能 - 强制任何实际存储在寄存器或其他地方的东西。
现在,这本身并不是什么大问题,但这是一个问题,因为它表明你并没有真正掌握安全工程或风险分析,如果你是一个大问题设计或实现真实的加密解决方案。坦率地说,你的帖子(至少对我来说)表明你还没有准备好构建或实现这样一个系统。
答案 1 :(得分:8)
您无法消除风险,但可以减轻风险。
创建一个静态内存区域,这是您存储明文密钥的唯一位置。并创建一个随机数据缓冲区,您将使用该缓冲区来清除未存储在此静态缓冲区中的任何键。
每当你从一个密钥文件或其他东西读取内存中的密钥时,你只能将它直接读入这个静态缓冲区,xor随机数据并将其复制到你需要的任何地方,并立即用零清除缓冲区。
您可以通过比较它们的蒙版版本来比较任意两个键。你甚至可以比较蒙面键的哈希值。
如果您需要使用明文密钥 - 例如生成一个哈希或验证它们的密钥以某种方式将屏蔽的xor#ed密钥加载到这个静态缓冲区中,然后再将其转换为明文并使用它。然后将零写回缓冲区。
取消屏蔽,操作和重新屏蔽的操作应该很快。不要让缓冲区长时间不受掩盖。
如果有人试图进行冷启动攻击,拔掉硬件上的插头,并检查内存芯片,那么只有一个缓冲区可以容纳一个明文密钥,并且可能在冷启动的特定瞬间攻击缓冲区将为空。
当对键进行操作时,您甚至可以在需要它之前解除密钥的一个单词,以便验证密钥,使得完整的密钥永远不会存储在该缓冲区中。
@update:我只是想在下面的评论中提出一些批评:
短语"通过默默无闻的安全"通常被误解了。在正式分析安全算法"默默无闻"或者隐藏非加密安全数据的方法不会增加加密算法的形式安全性。在这种情况下也是如此。鉴于密钥存储在用户计算机上,并且必须由该计算机在该计算机上使用,因此无法使该计算机上的密钥加密安全。无论您在某个时刻使用什么进程来隐藏或锁定数据,程序都必须使用它,并且确定的黑客可以在代码中放置断点并观察程序何时使用数据。但是这个帖子中没有任何建议可以消除这种风险。
有人建议OP找到一种方法来使用带有锁定内存芯片的特殊硬件或某种操作系统锁定芯片的方法。这在加密方面不再安全。最终,如果您对机器有物理访问权限,那么足够坚定的黑客可以在内存总线上使用逻辑分析仪并恢复任何数据。除了OP已经声明目标系统没有这种专用硬件。
但这并不意味着您无法采取任何措施来降低风险。使用最简单的访问密钥 - 密码。如果您可以对机器进行物理访问,则可以将其放入密钥记录器中,或者获取正在运行的程序的内存转储等。因此,正确地说,密码不会比粘贴在键盘上的便利贴上用明文写的密码更安全。然而,每个人都知道在粘滞便笺上保留密码是一个坏主意,这对程序以明文回复用户密码是不好的做法。当然,实际上,这大大降低了攻击者的标准。然而,正式使用密码的便利贴也同样安全。
我上面提出的建议具有真正的安全优势。除了' xor'之外,所有细节都不重要。屏蔽安全密钥。并且有一些方法可以使这个过程变得更好。 Xor的密钥将限制程序员必须考虑作为攻击向量的位置数。一旦密钥是xord,你可以在你的程序中拥有不同的密钥,你可以复制它们,将它们写入文件,通过网络发送等等。除非攻击者拥有xor缓冲区,否则这些都不会危害你的程序。所以有一个单一的缓冲你需要担心。然后,您可以放松系统中的每个其他缓冲区。 (你可以mlock或VirtualLock那个缓冲区)
一旦清除了xor缓冲区,就可以永久安全地消除攻击者从程序内存转储中恢复任何密钥的可能性。您可以根据地点数量和可以恢复钥匙的时间来限制您的曝光率。而且您正在建立一个系统,允许您轻松使用密钥,而不必担心每个操作对象都包含关于可以轻松恢复密钥的密钥的对象。
因此,您可以想象一个系统,其中键重新计算xor缓冲区,并且当不再需要所有键时,您将零并删除xor缓冲区,并且所有键都将变为无效且无法访问,而无需您追踪它们并担心关于内存页面是否被换出并仍然保留明文密钥。
你也不必保持随机数据的缓冲区。例如,您可以使用加密安全随机数生成器,并根据需要使用单个随机种子生成xor缓冲区。攻击者可以恢复密钥的唯一方法是访问单个生成器种子。
您还可以根据需要在堆栈上分配明文缓冲区,并在完成时将其归零,以使堆栈极不可能离开芯片缓存。如果完整的密钥永远不会被解码,但是根据需要一次解码一个字,即使访问堆栈缓冲区也不会显示密钥。
答案 2 :(得分:5)
没有独立于平台的解决方案。您要解决的所有威胁都是特定于平台的,因此解决方案也是如此。没有法律要求每个CPU都有寄存器。没有法律要求CPU拥有缓存。另一个程序访问程序RAM的能力,实际上是其他程序的存在,是平台细节。
您可以创建一些功能,例如“分配安全内存”(默认调用malloc
)和“免费安全内存”(默认调用memset
然后调用free
)和然后使用那些。您可能需要在需要其他东西的平台上执行其他操作(例如锁定内存以防止密钥在交换中清空)。
答案 3 :(得分:2)
除了上面非常好的评论之外,您还必须考虑即使 IF 您成功地将密钥存储在寄存器中,该寄存器内容很可能会在中断时存储在内存中进来,和/或当另一个任务在机器上运行时。当然,有机器访问机器的人可以运行调试器并检查寄存器。调试器可能是“电路仿真器”,如果密钥足够重要,有人会在这样的设备上花费几千美元 - 这意味着目标系统上根本没有软件。
另一个问题当然是多少重要。钥匙来自哪里?有人打字吗?如果没有,并存储在其他地方(在代码中,在服务器上等),那么它们将在某个时刻存储在内存中,即使您在实际使用密钥时成功将它们保留在内存中。如果某人正在输入,那么某人是否存在安全风险,迫使知道钥匙的人泄露钥匙?
答案 4 :(得分:2)
正如其他人所说,在通用计算机上没有安全的方法可以做到这一点。另一种方法是使用Hardware Security Module(HSM)。
这些提供:
您可以使用HSM的API执行您需要的加密操作(假设它们有些标准),而不会在HSM之外暴露未加密的密钥。
答案 5 :(得分:1)
如果您的平台支持POSIX,您可能希望使用mlock
来阻止您的数据被分页到交换区域。如果您正在为Windows编写代码,则可以使用VirtualLock
代替。
请记住,如果您要求数据在RAM中的任何时间点都是未加密的形式,那么就没有绝对的方法来保护敏感数据不被泄露(我们在这里谈论的是简单的RAM) ,没有像TrustZone那样的幻想。所有你能做的(并希望)是尽量减少数据保持未加密的时间,以便对手有更少的时间来采取行动。
答案 6 :(得分:0)
正如提到的其他答案,您可以实施软件解决方案,但如果您的程序在通用计算机和操作系统上运行且攻击者可以访问您的计算机,则无法保护您的敏感数据。如果您的数据非常合理并且攻击者可以物理访问该计算机,则通用软件解决方案是不够的。
我曾经看到一些平台处理非常敏感的数据,这些数据有一些传感器可以检测某人是否在物理上访问机器,并且在这种情况下会主动删除数据。
您已经提到过冷启动攻击,问题是RAM中的数据可以在关闭一般RAM后几分钟内访问。
答案 7 :(得分:0)
如果您的用户模式应用程序和您尝试保护的内存来自其他用户模式进程,请尝试CryptProtectMemory api(不适用于持久性数据)。