根据MSDN SecureString内容加密以获得额外的安全性,因此如果程序被交换到磁盘,则无法嗅探字符串内容。
我想知道这种加密怎么样?算法是固定的,因此要么是熟知的,要么是免赔额的(比如工业算法中广泛使用的七种算法之一),并且程序中必须有一个密钥。因此,攻击者可以获取加密的字符串,获取密钥并解密数据。
这种加密如何有用?
答案 0 :(得分:18)
我引用了一篇关于用于推导密钥的DPAPI的文章。这应该回答大多数关于SecureString的问题。
是的,SecureString有缺点并且不完全安全,有方法可以访问数据,例如,在MSDN上提到将Hawkeye注入到进程中作为提取SecureString的方法。我没有亲自核实这个断言。
DAPI是一种基于对称的加密技术,这意味着它使用相同的密钥来加密和解密数据。在了解如何使用DAPI的一些示例之前,值得介绍DAPI如何管理其密钥。在大多数情况下,DAPI密钥管理过程是隐形的,您通常不需要担心它,这是DAPI是一个好方法的主要原因。
在介绍中我写道,主密钥是从用户的登录密码生成的。这不是完整的图片。实际发生的是Windows使用用户的登录密码生成主密钥。此主密钥使用用户密码进行保护,然后与用户的配置文件一起存储。然后,该主密钥用于导出许多其他密钥,而这些密钥用于保护数据。
Windows之所以这样做,是因为它允许应用程序在生成单个密钥的过程中添加称为熵的附加信息。您会看到在用户的登录帐户下运行的每个应用程序是否使用相同的密钥,然后每个应用程序都可以取消保护受DAPI保护的数据。有时您可能希望应用程序能够共享受DAPI保护的数据;但是,有时你不会。通过让应用程序为密钥的生成贡献熵,该密钥变为特定于应用程序,并且如果它们知道熵,则该应用程序保护的任何数据都只能再次受到保护。
虽然生成主密钥,然后使用该主密钥生成其他密钥来进行实际加密,但看起来似乎是一个冗长的方法,它确实有一个主要优势。由于在用户密码保护的主密钥和用于保护数据的实际密钥之间存在额外的抽象级别,这意味着当用户更改其密码时,只需要重新保护主密钥;没有受保护的数据需要重新保护。由于主密钥的大小比数据小得多,因此可以显着节省性能。
当用户的密码更改时,当然会生成新的主密钥。然后,这个新的主密钥用于生成新的单个密钥。但是,由于所有先前生成的单个密钥都是从旧主密钥派生的,因此Windows需要存储所有以前的主密钥。 Windows永远不会忘记主密钥,所有受保护的数据都标有GUID,指示使用哪个主密钥来保护数据。因此,在适应性方面,DAPI能够应对用户密码的更改,同时确保a)受保护的数据不需要重新保护,以及b)用于先前保护数据的密钥仍然可用,以及c )它会自动完成所有这些。
除非计算机是域的成员,否则DAPI只能在用于保护它的同一台计算机上使用不受保护的数据。
除了允许用户级别保护之外,主密钥基于用户密码,并且一个用户的受保护数据不能被其他用户保护,DAPI还提供机器级保护,因为主密钥基于机器特定信息。机器级主密钥允许应用程序存储受保护的数据,以便应用程序的所有用户不受其保护。已经描述的过程的唯一区别是主密钥是根据机器特定信息而不是用户特定信息生成的。
答案 1 :(得分: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
.
使用RtlDecryptMemory
(SystemFunction041
)解密。
我确信编译器也会对SecurityCriticalAttribute
执行某些操作。
编辑使用4.0反映了这一点。其他版本可能不同。
答案 2 :(得分:7)
正如其他人已经回答的那样,SecureString
的内容是使用DPAPI加密的,因此密钥不会存储在您的应用程序中,它们是操作系统的一部分。我不是100%肯定,但我认为SecureString
使用特定于用户的密钥,因此即使另一个进程获得对内存块的访问权限,它也必须在相同的凭据下运行为了简单地使用DPAPI解密内容。即使没有,机器密钥(理论上)也可以防止字符串在转移到另一个系统时被轻易解密。
SecureString
更重要的是&当你使用它。它应该用于存储需要在“延长”时间段内保留在内存中的字符串数据,但这些数据在解密形式中并不常用。在某些时候,您将不得不将其解密为常规旧System.String
或System.Char[]
。这是它在内存中最容易受到攻击的时候。如果你经常这样做,那么你有多个解密字符串副本在内存中漂浮等待收集。
作为一般规则,如果我正在读取我需要保留以便不经常使用的加密数据(例如登录凭证)(例如,PayPal或Amazon API交互),那么我将这些凭证存储/缓存为{{1然后根据需要解密它只需要足够长的时间来进行Web服务调用,并确保任何解密副本的生命周期只有几行代码。
使用关键块或类似提示CLR在使用解密字符串时不应进行上下文切换可能也是明智之举,以提高在缓存或交换内存之前收集任何解密副本的机会
答案 3 :(得分:2)
借助DPAPI的魔力:
此类使用Data Protection API(DPAPI)保护的内存模型存储其数据。换句话说,数据总是以加密形式存储,而是存储在SecureString中。加密密钥由本地安全机构子系统(LSASS.EXE)管理,通过DPAPI,数据可以通过进程间通信进行解密。