密码存储在内存中是否安全?

信息安全 密码 操作系统 记忆
2021-09-06 21:30:18

我刚刚意识到,在任何语言中,当您将密码保存在变量中时,它都会以纯文本形式存储在内存中。

我认为操作系统完成了它的工作并禁止进程访问彼此分配的内存。但我也认为这在某种程度上是可以绕过的。所以我想知道它是否真的安全,是否有更安全的方法来存储密码以确保外部进程无法访问它们。

我没有指定操作系统或语言,因为我的问题很笼统。这是一个计算机素养问题,而不是一个特定目的的问题。

4个回答

你触到了痛处……

从历史上看,计算机是大型机,许多不同的用户在同一物理机器上启动会话和进程。类 Unix 系统(例如 Linux),还有 VMS 及其相关系统(该家族包括 NT 线的所有 Windows,因此 2000、XP、Vista、7、8...),已构建为支持主机模型。

因此,硬件提供特权级别操作系统的核心部分是内核,它以最高特权级别运行(是的,我知道虚拟化方面存在一些微妙之处)并管理特权级别。应用程序在较低级别运行,并被内核强制阻止读取或写入彼此的内存。应用程序从内核中按页(通常为 4 或 8 kB)获取 RAM 。试图访问属于另一个应用程序的页面的应用程序被内核阻止,并受到严厉惩罚(“分段错误”,“一般保护错误”......)。

当应用程序不再需要某个页面时(特别是当应用程序退出时),内核会控制该页面并将其交给另一个进程。现代操作系统在将页面归还之前会“空白”页面,其中“空白”意味着“用零填充”。这可以防止将数据从一个进程泄漏到另一个进程。请注意,Windows 95/98/Millenium 没有空白页,并且可能会发生泄漏……但这些操作系统是为每台机器的单个用户设计的。

当然,有一些方法可以逃避内核的愤怒:有一些门道可供具有“足够特权”(与上述特权不同)的应用程序使用。在 Linux 系统上,这是ptrace()内核允许一个进程通过 ptrace() 读取和写入另一个进程的内存,前提是两个进程在相同的用户 ID 下运行,或者执行 ptrace() 的进程是“根”进程。Windows 中也存在类似的功能。

底线是 RAM 中的密码并不比操作系统允许的安全。根据定义,通过将一些机密数据存储在进程的内存中,您信任操作系统不会将其泄露给第三方。操作系统是你的朋友,因为如果操作系统是敌人,那么你就彻底输了。


有趣的来了。由于操作系统强制执行进程分离,许多人试图找到突破这些防御的方法。他们发现了一些有趣的事情......

  • 应用程序看到的“RAM”不一定是真正的“内存”。内核是幻想大师,它给出了不一定存在的页面。这种错觉是通过将 RAM 内容与磁盘上的专用空间交换来维持的,其中可用空间较多;这称为虚拟内存应用程序不需要意识到这一点,因为内核会在需要时带回页面(当然,磁盘比 RAM 慢得多)。一个不幸的结果是一些数据,据称保存在RAM中,使其成为物理介质,直到被覆盖为止。特别是,如果断电,它会停留在那里。这允许攻击者抓住机器并逃跑,以便稍后检查数据。或者当机器退役并在 eBay 上出售时可能会发生泄漏,并且系统管理员忘记擦除磁盘内容。

    Linux 提供了一个称为mlock()的系统,它可以防止内核将某些特定页面发送到交换空间。由于在 RAM 中锁定页面会耗尽其他进程的可用 RAM 资源,因此您需要一些特权(再次为 root)才能使用此功能。

    一个更严重的情况是,跟踪您的密码在 RAM 中的实际位置并不一定容易。作为程序员,您可以通过编程语言提供的抽象来访问 RAM。特别是,使用垃圾收集的编程语言可以透明地复制 RAM 中的对象(因为它确实有助于许多 GC 算法)。因此,大多数编程语言都会受到影响(例如 Java、C#/.NET、Javascript、PHP ......这个列表几乎是无穷无尽的)。

  • 冬眠带来了同样的问题,复仇。从本质上讲,休眠必须将整个 RAM 写入磁盘——这可能包括被锁定的页面,甚至 CPU 寄存器的内容。为了避免通过休眠导致泄漏,您必须采取严厉措施,例如加密整个磁盘——这自然意味着每当您唤醒机器时都要输入解锁密码。

  • 大型机模型假设它可以运行多个相互敌对的进程,但仍保持完美的和平与隔离。现代硬件使这变得非常困难。当两个进程在同一个 CPU 上运行时,它们共享一些资源,包括缓存内存;缓存中的内存访问比其他地方快得多,但缓存大小非常有限。这已被用来从另一个进程恢复一个进程使用的加密密钥。已经开发了使用其他类似高速缓存的资源的变体,例如CPU中的分支预测。虽然对该主题的研究集中在作为高价值机密的加密密钥上,但它实际上可以应用于任何数据。

    同样,视频卡可以进行直接内存访问是否不能滥用 DMA 从其他进程读取或写入内存取决于未记录的硬件、闭源驱动程序和内核如何协作以实施适当的访问控制。我不会把我的最后一件衬衫赌在上面...


结论:是的,当您将密码存储在 RAM 中时,您相信操作系统会对其保密。是的,这项任务很艰巨,在现代系统上几乎是不可能的。如果某些数据是高度机密的,你真的不应该使用大型机模型,并且不允许潜在的敌对实体在你的机器上运行他们的代码。

(顺便说一句,这意味着托管的虚拟机和云计算最终不可能是安全的。如果您对安全性很认真,请使用专用硬件。)

我认为操作系统完成了他的工作并避免进程访问其他分配的内存。但我认为这在某种程度上是可行的。

是的,可以访问另一个进程的内存。在 Windows 上,这相当于拥有SE_DEBUG_PRIVILEGE并使用ReadProcessMemory()来提取您想要的信息。

您可以从 Windows 驱动程序执行相同的操作,尽管由于当前分页到下半部分的内存存在一些复杂性,因此很难正确处理。

在任何一种情况下,您都需要有权访问管理帐户,或者错误分配的进程SE_DEBUG_PRIVILEGE,或者具有此权限的进程可以被说服执行您需要的操作。

因此,归结为确保没有人可以升级以获得这些特权。更现实地说,我们确保只有受信任的用户才能拥有这些权限。如果您有权访问管理帐户,则可以很容易地直接从另一个帐户的进程内存中读取密码。

在linux下,你可以用ptrace()andPTRACE_PEEK_DATA选项实现同样的事情。

您可能会问为什么这些功能首先存在?实际上,它们对于调试过程非常方便。可以想象,这是管理员用户可能希望做的事情。相比之下,普通用户不需要也应该彼此隔离。

这就是为什么人们在一段时间内建议在管理员帐户下运行所有​​内容通常不是一个好主意的原因。

我在消费电子领域工作,这里的安全性与服务器环境有些不同。在这里,我们必须假设产品处于恶劣的环境中。因此,出于订阅者管理的目的,密钥是安全的。第一道防线是 SoC 具有隐藏的寄存器,即使操作系统也无法实际访问,它们在制造时被烧毁,芯片熔丝被烧断,阻止访问。我们自己也看不到密钥,因为这在生产车间是不安全的,而是预先包装了我们不知道的批量密钥,只有芯片供应商和创建密钥的人知道(主密钥在芯片中使用后会被破坏)。一旦芯片加载了秘密,它就可以被锁定并且永远不会*解锁。

如果您无法访问密钥,那么您如何解密任何内容?借助 SoC 上的加密协处理器,您可以加载关键位置,而无需实际知道内部的值。您也永远看不到加密处理器的微代码,因为即使在制造时您也无法注入任何东西。

如果您有不适合大量芯片寄存器的密钥或证书,那么您必须将它们存储在 RAM 和/或NVM中,但是由于加密处理器,您不需要公开这些值。RAM 或 NVM 本身可以被芯片用除了它自己以外的任何人都不知道的密钥来加扰。

最后,与计算机不同的是,安全的嵌入式系统也具有一定的物理安全性。RAM 连接轨道不允许位于 PCB 的表面(“埋孔”)。这是因为如果 RAM 中有明确的元素,那么您需要限制访问,可能会减慢或冻结 CPU,然后再探测 RAM。

最后,对于智能卡,可以拦截 SoC 和卡之间的交易。这就是所谓的“卡共享”,解决这个问题的方法是对卡和 SoC 之间的交易进行加密,并将它们相互绑定,使它们不能交换或共享。

我知道 DRM/内容安全在互联网上的某些人中不受欢迎,但我想我会分享一些来自具有某些特定安全要求的行业的高级概念。

*理论上。

Linux 平台上正在做一些工作以禁止访问正在运行的进程的内存,即使是超级用户也是如此。使用 SELinux,您可以从 Fedora 17 开始:SELinux Deny Ptrace