我只是意识到,无论用哪种语言,当您将密码保存在变量中时,密码都会以纯文本格式存储在内存中。分配的内存。但是我也认为这是可以绕开的。因此,我想知道它是否真的安全,是否有一种更安全的方式来存储密码以确保外部进程无法访问它们。很一般。这是一个计算机素养问题,而不是一个特定目的的问题。

评论

这实际上是加密的弱点。任何未加密的值或等待加密的值均以纯文本形式存储在内存中。

您可能会在程序员问题中找到一些有用的背景。

我记得Slashdot上有关利用DRAM衰落延迟的取证技术的文章:将RAM芯片从运行中的计算机足够快地移动到另一台计算机上(数量完全在人的能力范围内),您可以轻松地丢弃全部内容。

虽然其他答案很好地涵盖了“安全为...”的细微差别,但如果您担心的话,您的平台/库可能具有SecureString或类似的设计,以最大程度地降低风险。一旦您指出使用完毕,这种构造可能会覆盖其自身的内存,并管理由垃圾回收等引入的自身副本的细微差别。

良好的安全预防措施是尽快覆盖包含密码的变量(在C / C ++中比Java更容易),而改用派生密钥(例如使用PBKDF2生成)。

#1 楼

您正在碰到一个痛处。

从历史上看,计算机是大型机,许多不同的用户在同一台​​物理计算机上启动会话和处理。构造了类似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上出售时,可能会发生泄漏,而sysadmin却忘记擦除磁盘上的内容。到交换空间。由于将页面锁定在RAM中可能会耗尽其他进程的可用RAM资源,因此您需要一些特权(再次是root用户)才能使用此功能。

加剧的情况是,跟踪密码在RAM中的实际位置不一定很容易。作为程序员,您可以通过编程语言提供的抽象来访问RAM。特别是,使用垃圾回收的编程语言可以透明地复制RAM中的对象(因为它确实对许多GC算法有帮助)。因此,大多数编程语言都受到了影响(例如Java,C#/。NET,Javascript,PHP等...几乎是无穷无尽的)。从本质上讲,休眠方式必须将整个RAM写入磁盘-这可能包括被锁住的页面,甚至包括CPU寄存器的内容。为避免因休眠而泄漏,您必须采取诸如加密整个磁盘之类的严厉措施-这自然意味着在您唤醒计算机时都输入了解锁密码。

大型机模型假定它可以运行多个彼此敌对的进程,却保持着完美的和平与孤立。现代硬件使这一点变得非常困难。当两个进程在同一CPU上运行时,它们共享一些资源,包括缓存。缓存中的内存访问比其他地方快得多,但是缓存的大小非常有限。已利用此方法从一个进程恢复另一个进程使用的加密密钥。已开发出使用其他类似缓存的资源的变体,例如CPU中的分支预测。虽然有关该主题的研究集中在加密密钥(这是高价值的秘密)上,但实际上它实际上可以应用于任何数据。是否可以滥用DMA来从其他进程读取或写入内存,取决于未记录的硬件,闭源驱动程序和内核如何协作以实施适当的访问控制。我不会打赌我的最后一件衬衫...



结论:是的,当您将密码存储在RAM中时,您就是在信任操作系统以保持机密性。是的,任务很艰巨,在现代系统上几乎是不可能的。如果某些数据是高度机密的,则您实际上不应该使用大型机模型,也不要允许潜在敌对实体在您的计算机上运行其代码。

(顺便说一下,这意味着托管虚拟机云计算并不能最终保证安全。如果您对安全性很重视,请使用专用硬件。)

评论


“虚拟机和云计算最终不可能安全”。我一直对云计算持怀疑态度。

– Antoine Pinsard
13年1月14日在22:07

还有一点要说明。在某个时间,某个时间长度的某个地方,纯文本必须仅驻留在“ RAM”中。如果明文从未暴露给任何人,则整个练习将变得毫无意义。结果是,表面上永远不会持久存在并且可以标记为“受保护”的RAM与在计算机系统范围之内一样安全。但是,您的观点是,内存(以及相同的操作系统保护)仅被视为安全的,因为替代方案是根本不使用计算机。

– KeithS
2013年1月14日23:13



为了最大程度地减少敏感数据以明文形式显示,各种语言提供了包装程序,使使用操作系统功能更容易防止分页。参见例如.Net SecureString。但是,这只能缓解问题,而不能解决问题。

– Skolima
13年1月15日在10:52

关于休眠的注意事项-如果文件本身被加密(例如,在dm-crypt上交换),则存储在其中的密码也被加密-DMA-火线通常允许设备中的DMA访问RAM(IOMMU会对此进行保护)。

– Maciej Piechotka
13年1月15日在11:10

我想指出的是,至少在Linux上,mlock不需要root priv。但是,如果您不是root用户,则可以锁定多少内存有严格的限制。

–空灵
13年3月18日在15:19

#2 楼


我认为操作系统可以完成他的工作,并避免进程访问其他人分配的内存。但是我认为这是可行的。


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

您可以从Windows驱动程序中执行相同的操作,尽管由于某些复杂性而很难解决

无论哪种情况,您都需要访问管理帐户,分配错误的进程SE_DEBUG_PRIVILEGE或具有此特权的进程被说服去做您需要的事情。

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

在linux下,可以使用ptrace()PTRACE_PEEK_DATA选项实现相同的操作。 br />
您可能会问为什么这些功能首先存在?实际上,它们在调试过程中非常方便。可以想象,这是管理员用户可能希望做的事情。相比之下,普通用户则不需要,并且应该彼此隔离。

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

评论


感谢您对Windows和GNU / Linux的简洁解释(我想对于其他Unix系统也是如此)。

– Antoine Pinsard
13年1月14日在20:54

@AntoinePinsard是的,如果他们实现ptrace,则很有可能!

–user2213
13年1月14日在21:04

如果您没有特殊权限,则可以获胜时可以读取同一用户上运行的其他进程的内存。

– CodesInChaos
13年1月14日在21:06

@Code为真。我不确定任何操作系统都能防御您的攻击!

–user2213
13年1月14日在21:24

@Sadaluk真正的问题发生在您没有运行在您帐户下运行的代码时。考虑脚本调用本地库,缓冲区溢出漏洞...

–用户
13年1月14日在22:19

#3 楼

我在消费电子领域工作,这里的安全性与服务器环境有些不同。在这里,我们必须假设该产品处于敌对环境中。因此,出于订户管理的目的,密钥是安全的。第一道防线是SoC具有隐藏的寄存器,即使操作系统实际上也无法访问这些寄存器,它们在制造时就被烧坏了,并且熔断了保险丝以阻止访问。同样,我们自己也看不到密钥,因为这在生产现场是不安全的,相反,它们被预先包装了一个我们不知道的批量密钥,只有芯片供应商和创建密钥的人才知道(主可以在芯片中使用后销毁密钥)。一旦芯片上装有机密信息,就可以将其锁定,并且永远不会*被解锁。通过SoC上的加密协处理器,您可以加载密钥位置,而无需实际知道其中的值。您也永远不会看到加密处理器的微代码,因为即使在制造时,您也无法注入任何东西。

如果密钥或证书不适合大量的芯片寄存器,则必须将它们存储在RAM和/或NVM中,但是由于使用了加密处理器,因此不需要暴露那些价值。 RAM或NVM本身可以用芯片来加密,而密钥本身是任何人都不知道的。

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

最后,对于智能卡,可以拦截SoC和卡之间的交易。这称为“卡共享”,解决方案是对卡和SoC之间的事务进行加密,并将它们彼此绑定,以使它们无法交换或共享。

我知道Internet上的某些人不欢迎DRM /内容安全,但是我想我会分享一些具有特定安全要求的行业的高级概念。

*理论上。

评论


+1。您知道现代笔记本电脑/台式计算机是否已在做类似的事情吗?我敢打赌,至少有几个行业(认为军事,政府)会对获得这种级别的安全性感兴趣。还是必须是完全定制的电子设备?

–mjuarez
2014年8月2日在21:58

从理论上讲,Microsoft可以使用Linux对EFI引导进行的最新更改来建立信任链,正如@mricon所说,SElinux可以帮助其他人。我也一直在考虑OKL4的高安全性,因为您可以将Linux之外的安全组件带到另一个OS。

– bob_dvb
2014年8月10日10:14



@mjuarez,可能感兴趣:减少TPM芯片。

– sampablokuper
'18 Apr 6在0:38



#4 楼

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

#5 楼

您使用的是哪种语言/平台?

如果是.NET,请查看PasswordBox控件和SecureString类。

SecureString类表示一种将密码存储在内存中而不让任何人都可以访问的方法-甚至是偷窥应用程序内存的黑客。

PasswordBox控件是一个包含SecureString的文本框,因此您可以从头到尾确保密码的安全。

评论


请不要只是发布链接作为您的答案。尽力阐述您的答案,然后才将链接发布为来源/信用。如果链接不见了,您的答案也将如此。

–洛伦佐·冯·马特宏峰
13年1月14日在19:35

@Lorenzo +1我同意。我习惯于通过一系列修改来发布答案,而不是一口气将其全部发布。尽管我不担心MSDN链接很快就会消失。 :)

– Giffyguy
13年1月14日在19:38

@Giffyguy-出于多种原因在.NET中使用SecureString是有意义的,但是它并不能阻止复杂的“偷窥您的应用程序内存的黑客”获取密码;它虽然增加了混淆。 SecureStrings将在内存中加密;但是,解密密钥也必定在内存中。但这仍然比内存中的纯文本pw好,因此它从未在coredump / swapfile / etc中公开。

– jimbob博士
13年1月14日在20:29

SecureString获得的收益非常有限。这是针对崩溃转储和交换文件的。它不能防止恶意程序访问您的进程内存。这些能够获取密码的应用程序不是安全漏洞,MS不会对其进行修补。

– CodesInChaos
13年1月14日在21:08



@CodesInChaos-确实如此。 SecureString使用数据保护API;在2010年进行了反向工程(不确定自那时以来MS是否已更改)。破解并非易事(例如,如果您拥有对系统的完全访问权限;在使用键盘记录器敲击SecureString之前捕获密码就更容易了)。但是,由于正在运行的应用程序必须能够对其进行解密,因此,复杂的分析(具有对磁盘/内存的完全访问权限)必须能够恢复它。

– jimbob博士
13年1月14日在22:08

#6 楼

不可以,以明文形式存储在RAM中的密码不应被认为是安全的。通常,在具有直接访问的接口(如FireWire,ExpressCard和Thunderbolt)的x86和x86-64体系结构上,这些接口可用于绕过操作系统内存保护,从而从内存中获取纯文本密码。

使用FireWire获得纯文本密码并非只是理论上的攻击。现在出售该软件以获取BitLocker,PGP和TrueCrypt加密磁盘的纯文本密码ElcomSoft解密BitLocker,PGP和TrueCrypt容器安全禁用火线/雷电,在Linux下修补DMA暴露。微软也有一个知识库文章,以缓解对BitLocker的Firewire和Thunderbolt的攻击阻止SBP-2驱动程序和Thunderbolt控制器以减少对BitLocker的1394 DMA和Thunderbolt DMA威胁。在Wikipedia DMA攻击中找到。

#7 楼

除了利用操作系统漏洞的所有软件攻击之外,如果攻击者可以物理访问您的计算机,它们还可以直接从内存中读取密钥。

评论


“如果攻击者可以物理访问您的计算机”,那么通常几乎所有的赌注都被认为是无效的,并且攻击者能够从内存中的变量中读取密码的能力通常是最少的问题。

–用户
13年1月14日在22:20



防止冷启动攻击的一种可能的保护措施是加密技术,该技术可以加密RAM的内容,并且仅将CPU寄存器用作“受信任”位置来存储加密密钥。签出例如

– a3nm
13年3月18日在9:35

#8 楼

您提出了一个有效的问题,而实际上,这通常是在与安全性相关的软件中解决的。当不再需要诸如密钥之类的敏感对象时,某些程序将不会简单地将内存交还给内存管理库或操作系统,而是首先通过覆盖敏感位来消除它们。

当然,一些程序需要持久地保持键。例如ssh-agent。因此,这些程序容易受到攻击。如果您是多用户计算机上的普通用户,则ssh-agent的动态内存将受到具有root privs并且可以查看计算机内存的任何部分的任何人的攻击。<​​br />
无论如何,甚至短暂使用键的程序仍然存在漏洞窗口。一微秒可能是CPU时间的永恒。恶意的超级用户甚至可以在某些指令上无限期地暂停程序,而该程序在内存中的某处具有纯文本格式的敏感数据。

因此,根据经验,不要执行任何安全性-计算机上的敏感计算(如果该计算机具有您不信任的任何用户或软件)以及不信任的操作系统,以防止这些用户或软件提升其特权,以便他们可以窥视您的密钥或明文数据。 />
使用任何安全客户端时,您都信任该程序及其整个平台,并且可以运行在预先安装或之后安装的每个程序中的硬件和每条机器指令上。

(所谓的“可信计算”并不能解决这个问题;它只是改变了恶棍的身份。)

评论


+1所谓的“可信计算”无法解决此问题;只会改变小人是谁

–woliveirajr
2013年1月15日15:52

既然如此,那么如何实现所有基于软件的drm? (可播放时间<3.0,宽屏电视,黄金时段等)

– davidkomer
16年6月16日在6:02

#9 楼

即使密钥已加密,鳕鱼启动攻击也可以检索您的密码:
查看此正在进行的冷启动攻击的视频。.
http://www.youtube.com/watch?v=JDaicPIgn9U

#10 楼

操作系统与运行中的应用程序的安全性始终存在一定程度的信任,除非您当然有时间阅读所有源代码并验证不存在漏洞利用程序。如果您有那个时间,那就不需要信任了。但这是不可能的。如果可能的话,最好在一台计算机上运行专有项目,并在另一台计算机上运行所有必须信任的内容。与基于信仰的解决方案相比,物理隔离可以很好地解决问题。

评论


你是绝对正确的。这就是为什么我(或至少尝试)仅在计算机上运行自由软件的原因。

– Antoine Pinsard
13年1月18日在14:59

您能否详细说明为什么操作系统和应用程序之间必须有任何信任?我认为,从理论上讲,使用足够的沙箱(root监狱,有限的权限等)应该可以安全地运行病毒。我并不是说这是实用或100%安全的,但应该可以完全沙漏不受信任的应用程序。

–吕克
13年3月18日在10:30



@Luc可以肯定,但这与沙盒无关。您没有在沙盒中运行日常任务,对吗?

–凯伊
2014年1月15日20:59



@Kaii如果我从事某些重要工作,则可以选择。

–吕克
2014年1月16日上午10:20

#11 楼

需要进行一些有意义的研究,以确保即使超级用户也无法访问存储在其他进程的内存中的机密。我从未真正完成过这项工作,因此这只是一个起点。这并不能阻止任何物理攻击,例如冷启动攻击。

在Linux上从根目录保留机密

#12 楼

这不能解决您的问题,尽管您可以使用一种技巧来最大程度地减少将密码或其他机密存储在内存中的时间,然后再将其清零。写入相同的内存,而不是分配具有不同值的新对象。例如,在Java中,您将使用byte[]而不是String来保存机密。

评论


我在读这篇文章,在想类似的东西。如果您需要将其存储在RAM中,那么在此期间密码不能加密吗?我知道它必须以纯文本形式存在,但是可以将其最小化。

–括号
2014年1月15日20:08

#13 楼

鉴于这可能适用于具有不同保护级别的许多操作系统,请牢记以下几点:


无论如何,您无法阻止密码在某些情况下进入内存点。如果有人可以实时访问应用程序的内存,那么您就无法阻止他们看到它。
密码通常比受保护的内容更有价值-用户重用密码,并且通过接受密码登录就可以达到某种程度即使密码保护的数据遭到破坏,也要对密码保密负责。通过使用慢速散列函数(PBKDF,scrypt,bcrypt)对用户密码进行散列并使用散列进行身份验证,可以在某种程度上减轻对冷存储器(液氮或休眠)的攻击所造成的损害。
从内存中清除用户密码是一种好习惯。正确执行此操作涉及许多陷阱,因此请确保使用适当的库:Windows Linux示例