从桌面应用程序使用时的PasswordVault安全性

And*_*kov 18 .net c# security wpf passwordvault

我想在我的桌面应用程序(基于WPF)中使用Windows.Security.Credentials.PasswordVault来安全地存储用户的密码.我设法使用此MSDN文章访问此Windows 10 API .

我做了一些实验,似乎可以从任何其他桌面应用程序读取从一个桌面应用程序(不是本机UWP应用程序)写入PasswordVault的任何数据.即使使用Desktop Bridge技术打包我的桌面应用程序,因此具有包标识也无法修复此漏洞.

任何想法如何解决这个问题,并能够从其他应用程序安全存储应用程序的数据?

更新:似乎PasswordVault没有为DPAPI增加额外的安全性.案件结案,结果为否定.

Llo*_*oyd 5

(据我对您的帖子的了解)

使用此类API的http://www.hanselman.com/blog/SavingAndRetrievingBrowserAndOtherPasswords.aspx可以提供有关阻止它的真正方法。您可能只想解密您的信息。

存储器访问限制很困难,用户执行的代码始终可由用户检索,因此很难对此进行限制。

您是否考虑过使用Windows数据保护API:https : //msdn.microsoft.com/zh-cn/library/ms995355.aspx

从源头直接获取 DPAPI是一项易于使用的服务,它将使必须保护敏感应用程序数据(例如密码和私钥)的开发人员受益

WDPAPI使用操作系统和Triple DES生成的密钥来加密/解密您的数据。这意味着您的应用程序不必生成这些密钥,这总是很好。

您还可以使用Rfc2898DeriveBytes类,该类使用伪随机数生成器来解密密码。它比大多数解密器更安全,因为没有实际的方法可以将结果从密码返回到密码。这仅对验证输入密码而不是再次取回密码非常有用。我本人从未真正使用过此功能,因此无法为您提供帮助。

https://msdn.microsoft.com/zh-CN/library/system.security.cryptography.rfc2898derivebytes(v=vs.110).aspx

另请参阅这篇文章,它给出了比我更好的解释方式。 如何安全保存用户名/密码(本地)?

如果我以某种方式误解了问题,请告诉我,我将尝试更新答案。

请注意,尽管现代/地铁应用程序仍可以通过其他方式访问,但不会出现此问题。

  • 保险柜使用DPAPI。您可以检查是否运行命令“ vaultcmd / listproperties:“ Web凭据”“ (4认同)

sty*_*ybl 5

残酷的事实是,在桌面应用程序中存储密码 100% 安全根本不可能。但是,您可以接近 100%。

关于您的原始方法,PasswordVault 使用Windows 内置的Credential Locker服务来安全地存储数据。Credential Locker 绑定到用户的个人资料。因此,通过 PasswordVault 存储您的数据本质上等同于保护数据的主密码方法,我将在下面详细讨论。唯一的区别是,这种情况下的主密码是用户的凭据。这允许在用户会话期间运行的应用程序访问数据。

注意:明确地说,我严格说的是以允许您访问纯文本的方式存储它。也就是说,将其存储在任何类型的加密数据库中,或者自己加密并将密文存储在某处。这种功能在密码管理器等程序中是必需的,但在只需要某种身份验证的程序中则不需要。如果这不是必需的,那么我强烈建议对密码进行散列,最好按照zaph答案中列出的说明进行。(Thomas Pornin这篇优秀文章中的更多信息)。


如果这必要的,事情会变得有点复杂:如果您想阻止其他程序(或我想的用户)能够查看明文密码,那么您唯一真正的选择就是对其进行加密。在 PasswordVault 中存储密文是可选的,因为如果您使用良好的加密,您唯一的弱点就是有人发现了您的密钥。因此密文本身可以存储在任何地方。这将我们带到了关键本身。

取决于你有多少密码实际上是试图存储每个程序实例,你可能没有约产生并安全地存储密钥担心在所有。如果您想存储多个密码,那么您可以简单地要求用户输入一个主密码,对其进行一些加盐和散列,并将结果用作所有其他密码的加密密钥。当需要解密时,请用户再次输入。如果您要存储多个密码,那么我强烈建议您采用这种方法。这是最安全的方法。但是,对于我帖子的其余部分,我将假设这不是一个可行的选择。

首先,我敦促您不要在每次安装时都使用相同的密钥。根据安全生成的随机数据,为程序的每个实例创建一个新实例。抵制“避免必须存储密钥”的诱惑,每次需要时都根据系统信息即时生成密钥。这与硬编码string superSecretKey = "12345";到您的程序中一样安全。攻击者很快就会弄清楚这个过程。


现在,存储它是真正棘手的部分。信息安全的一般规则如下:

一旦您可以物理访问,就没有什么是安全的

所以,理想情况下,没有人会这样做。将加密密钥存储在适当保护的远程服务器上可以最大限度地减少它被攻击者恢复的机会。关于服务器端安全的书已经写了整整一本书,所以我不会在这里讨论这个。

另一个不错的选择是使用 HSM(硬件安全模块)。这些漂亮的小设备专为这项工作而打造。访问存储在 HSM 中的密钥几乎是不可能的。但是,此选项仅在您确定每个用户的计算机都具有其中之一时才可行,例如在企业环境中。

.Net 通过配置系统提供了各种解决方案。您可以将密钥存储在app.config. 这通常用于保护连接字符串。有很多关于如何做到这一点的资源。我推荐这篇精彩的博客文章,它会告诉你你需要知道的大部分内容。


我之前说过不要简单地动态生成密钥的原因是,就像将它作为变量存储在代码中一样,你完全依赖混淆来保证它的安全。这种方法的问题在于它通常不会。但是,有时您别无选择。进入白盒密码术

白盒密码学本质上是将混淆发挥到极致。即使在攻击者可以访问并且可以修改字节码的白盒场景中,它也是有效的。它是通过默默无闻实现安全的缩影。与仅仅持续隐藏(信息安全代表该string superSecretKey方法)或在需要时生成密钥相反,白盒密码术本质上依赖于即时生成密码本身

整篇论文都写在上面,很难写出一个正确的实现,你的里程可能会有所不同。只有当您真的真的 很想尽可能安全地执行此操作时,才应该考虑这一点。


然而,混淆仍然是混淆。它真正能做的就是减缓攻击者的速度。我必须提供的最终解决方案可能看起来倒退,但它有效:不要以数字方式隐藏加密密钥。把它藏起来。让用户在需要加密时插入 USB 驱动器,(安全地)生成随机密钥,然后将其写入 USB 驱动器。然后,每当需要解密时,用户只需将驱动器放回原处,您的程序就会从中读取密钥。

这有点类似于主密码方法,因为它让用户来保证密钥的安全。但是,它有一些显着的优点。例如,这种方法允许使用大量加密密钥。一个可以放入仅 1 兆字节文件的密钥可能需要数十亿年才能通过蛮力攻击破解。另外,如果密钥被发现,用户只能怪自己。


总之,看看您是否可以避免必须存储加密密钥。如果不能,请避免不惜一切代价将其存储在本地。否则,您唯一的选择就是让黑客尽可能难以弄清楚。无论您选择如何操作,请确保每个密钥都不同,这样即使攻击者找到了一个,其他用户的密钥也是安全的。