2011-08-08 29 views
33

根据MSDN SecureString的内容是加密为了更加安全,因此如果程序交换到磁盘时,字符串内容不能被嗅探。SecureString如何“加密”并仍然可用?

我想知道这样的加密可能性如何?该算法将是固定的,因此可以是已知的或可抵扣的(例如七种工业算法中广泛使用的算法之一),并且程序中必须有一个关键字。所以攻击者可以获取加密的字符串,获取密钥并解密数据。

这样的加密如何有用?

+0

它并没有说它是安全的,只是*更安全* –

+0

@Mark Peters:这就是为什么我说*额外的安全*。 – sharptooth

+0

你可以用crypto.SE来问这个问题 - 非常有话题 –

回答

15

我从一篇关于DPAPI的文章引用,它是用来派生密钥的。这应该回答你关于SecureString的大多数问题。

是的,SecureString有缺点,并不完全安全,有办法访问数据,例如,注入Hawkeye到进程中提到MSDN作为一种方式来提取SecureString。我没有亲自验证这一说法。

DAPI密钥管理

DAPI是基于对称加密技术中,这意味着它使用相同的密钥来加密和解密数据。在介绍如何使用DAPI的例子之前,有必要介绍DAPI如何管理密钥。大多数情况下,DAPI密钥管理过程是不可见的,您通常不需要担心,这是DAPI是一种好方法的主要原因。

在介绍中我写道,主密钥是从用户的登录密码生成的。这不是完整的图片。实际发生的事情是,Windows使用用户的登录密码来生成主密钥。此主密钥使用用户的密码进行保护,然后与用户的配置文件一起存储。这个主密钥然后被用来派生许多其他密钥,并且这些密钥用于保护数据。

Windows为什么会这样做是因为它允许应用程序向生成个别密钥的过程中添加额外的信息,称为熵。您会看到,在用户的登录帐户下运行的每个应用程序是否使用了相同的密钥,那么每个应用程序都可以解除DAPI保护的数据的保护。有时您可能希望应用程序能够共享受DAPI保护的数据;但是,有时你不会。通过让应用程序将熵贡献给密钥的生成,那么该密钥变为应用程序特定的,并且任何受该应用程序保护的数据如果知道熵,则只能再次不受保护。

尽管生成主密钥,然后使用该主密钥生成其他密钥以进行实际加密,但看起来像是一种冗长的方法,但确实有一个主要优势。由于用户密码保护的主密钥和用于保护数据的实际密钥之间存在额外的抽象级别,这意味着当用户更改其密码时,只需要重新保护主密钥;所有受保护的数据都不需要重新保护。由于主密钥的尺寸比数据小得多,因此节省了显着的性能。

当用户的密码发生变化时,当然会生成一个新的主密钥。这个新的主密钥然后用于生成新的个体密钥。但是,由于所有以前生成的单个密钥都是从旧的主密钥导出的,因此Windows需要存储之前所有的主密钥。 Windows永远不会忘记主密钥,所有受保护的数据都会标记一个GUID,以指示哪个主密钥用于保护数据。因此,就适应性而言,DAPI能够应对用户密码的变化,同时确保a)受保护的数据不需要被重新保护,以及b)用于保护数据的密钥仍然可用,以及c) )它会自动为你做这一切。

除非计算机是域的成员DAPI只能在用于保护它的同一台计算机上提供未受保护的数据。

除了允许用户级别的保护,由于主密钥基于用户密码,并且受保护的数据对于一个用户不会受到其他用户的保护,所以DAPI还提供机器级保护,因为主密钥基于机器具体信息。机器级主密钥允许应用程序存储受保护的数据,以便应用程序的所有用户都可以不受保护。已经描述的过程中唯一的区别是主密钥是从机器特定的信息生成的,而不是用户特定的信息。

+1

+1让我们知道Hawkeye –

+0

我认为从发布的文章中拿掉的关键是“大多数情况下DAPI密钥管理过程是不可见的你通常不需要担心“。就在那里,我倾向于定制解决方案。足够好的保护并不总是,很好,足够好。 –

+0

注意:截至05/18/2017,文章链接返回404:http://www.dsmyth.net/wiki/Print.aspx?Page=StudyNotes_DAPI – iokevins

11

我看了一下它的代码,它使用Windows的advapi32来做它的肮脏的工作。所以密钥不会存储在应用程序的内存中。

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
internal static int SystemFunction040([In, Out] SafeBSTRHandle pDataIn, [In] uint cbDataIn, [In] uint dwFlag) 

这是更好地为RtlEncryptMemory.

它进行解密RtlDecryptMemorySystemFunction041)。

我确定编译器也会对SecurityCriticalAttribute做些什么。

编辑这反映了使用4.0。其他版本可能与不同。

2

通过DPAPI的魔力:

该类存储使用受保护的内存模型数据保护API(DPAPI)其数据。换句话说,数据总是以加密的形式存储在SecureString中。加密密钥由本地安全授权子系统(LSASS.EXE)管理,通过DPAPI可以通过进程间通信解密数据。

7

正如其他人已经回答,SecureString的内容使用DPAPI进行加密,因此密钥不存储在您的应用程序中,它们是操作系统的一部分。我不是100%肯定的,但我会假设SecureString使用用户特定的密钥,以便即使另一个进程访问该内存块,它也必须在相同的凭据下运行,以便简单解密使用DPAPI的内容。即使不是,机器密钥(理论上)也可以防止字符串在传输到另一个系统时被轻易解密。

SecureString更重要的是当你使用它时如何&。它应该用于存储需要在“扩展”时间段内保留在内存中的字符串数据,但是这些数据在解密形式中并不经常需要。在某些时候,你将不得不将它解密为普通的旧版本System.StringSystem.Char[]。这是记忆中最脆弱的时候。如果你经常这样做,那么你有多个解密字符串的副本在内存中等待收集。作为一般规则,如果我读取我需要保留的经常使用(例如,PayPal或Amazon API交互)的加密数据(例如登录凭证),那么我将这些凭证存储/缓存为SecureString,然后根据需要对其进行解密,只需足够长的时间以便进行Web服务调用,并确保任何解密副本的生命周期仅为几行代码。

使用关键块或类似的方式向CLR提示,在解密的字符串正在使用时不应该进行上下文切换,以提高在缓存内容之前收集任何解密的副本的机会,或者交换。

相关问题