【问题标题】:How is SecureString "encrypted" and still usable?SecureString 如何“加密”并且仍然可用?
【发布时间】:2011-10-22 08:56:51
【问题描述】:

根据 MSDN SecureString,内容已加密以提高安全性,因此如果将程序交换到磁盘,则无法嗅探字符串内容。

我想知道这种加密是如何实现的?该算法将是固定的,因此要么是众所周知的,要么是可扣除的(比如工业算法中广泛使用的七种算法之一),并且程序中的某处必须有一个密钥。因此攻击者可以获取加密字符串,获取密钥并解密数据。

这样的加密有什么用?

【问题讨论】:

  • 没说安全,只说更安全
  • @Mark Peters:这就是我说额外安全的原因。
  • 你可以在 crypto.SE 上问这个问题——那里很热门

标签: c# .net security encryption securestring


【解决方案1】:

我查看了它的代码,它使用 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 进行处理。

edit 这反映在 4.0 中。其他版本可能不同。

【讨论】:

    【解决方案2】:

    我引用了一篇关于 DPAPI 的文章,该文章用于派生密钥。这应该可以回答您对 SecureString 的大多数问题。

    是的,SecureString 有缺点并且不是完全安全的,有一些方法可以访问数据,例如,在 MSDN 上提到将Hawkeye 注入进程中作为提取 SecureString 的一种方法。我没有亲自验证过这种说法。

    DAPI 密钥管理

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

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

    Windows 这样做的原因是它允许应用程序在生成单个密钥的过程中添加称为熵的附加信息。您会看到如果在用户的登录帐户下运行的每个应用程序都使用相同的密钥,那么每个应用程序都可以取消保护 DAPI 保护的数据。有时您可能希望应用程序能够共享受 DAPI 保护的数据;但是,有时您不会。通过让应用程序为密钥的生成贡献熵,那么该密钥就成为特定于应用程序的密钥,并且受该应用程序保护的任何数据只有在他们知道熵的情况下才能再次不受保护。

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

    当用户的密码更改时,当然会生成一个新的主密钥。然后使用这个新的主密钥来生成新的个人密钥。但是,由于以前生成的所有单独密钥都是从旧主密钥派生的,因此 Windows 需要存储所有以前的主密钥,它确实如此。 Windows 永远不会忘记主密钥,并且所有受保护的数据都标有 GUID,该 GUID 指示用于保护数据的主密钥。因此,就适应性而言,DAPI 能够应对用户密码的更改,同时确保 a) 受保护的数据不需要重新保护,b) 用于先前保护数据的密钥仍然可用,以及 c ) 它会自动为您完成这一切。

    除非计算机是域的成员,否则 DAPI 只能在用于保护它的同一台计算机上不受保护的数据。

    除了允许用户级保护,主密钥基于用户密码,一个用户的受保护数据不能不受另一用户的保护,DAPI 还提供机器级保护,因为主密钥基于机器特定信息。机器级主密钥允许应用程序存储受保护的数据,使其不受应用程序所有用户的保护。已经描述的过程中唯一的区别是主密钥是根据机器特定信息而不是用户特定信息生成的。

    【讨论】:

    • 我认为从发布的文章中可以看出的关键是“在大多数情况下,DAPI 密钥管理过程是不可见的,您通常不需要担心它”。就在那里,我倾向于定制解决方案。足够好的保护并不总是足够好。
    • 注意:截至 2017 年 5 月 18 日,文章链接返回 404:dsmyth.net/wiki/Print.aspx?Page=StudyNotes_DAPI
    【解决方案3】:

    借助 DPAPI 的魔力:

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

    【讨论】:

      【解决方案4】:

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

      SecureString 更重要的是如何以及何时使用它。它应该用于存储需要在内存中保留“延长”时间段的字符串数据,但在解密形式中并不经常需要这些数据。在某些时候,您将不得不将其解密为普通的旧 System.StringSystem.Char[]。这是它在记忆中最脆弱的时候。如果你经常这样做,那么你有多个解密字符串的副本漂浮在内存中等待收集。

      作为一般规则,如果我正在读取需要保留以供不经常使用的加密数据(例如登录凭据)(例如,PayPal 或 Amazon API 交互),那么我会将这些凭据存储/缓存为 SecureString ,然后根据需要解密它,只需要足够长的时间进行 Web 服务调用,并确保任何解密副本的生命周期只有几行代码。

      使用关键块或类似的块来提示 CLR 在使用解密字符串时不应进行上下文切换可能也是明智之举,以提高在缓存或交换内存之前收集任何解密副本的机会.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-02
        • 1970-01-01
        相关资源
        最近更新 更多