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

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

我做了一些实验,看来从一个桌面应用程序(不是本机UWP应用程序)写入PasswordVault的任何数据都可以从任何其他桌面应用程序中读取。 即使使用Desktop Bridge技术打包我的桌面应用程序,因此具有Package Identity也无法解决此漏洞。

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

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

(这是我对你的post的理解)

使用这些API时,没有真正的方法可以阻止桌面应用程序之间的数据访问http://www.hanselman.com/blog/SavingAndRetrievingBrowserAndOtherPasswords.aspx详细介绍了它。 您可能只想解密您的信息。

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

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

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

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

您还可以使用Rfc2898DeriveBytes类,它使用伪随机数生成器来解密您的密码。 它比大多数解密器更安全,因为没有实际的方法可以从结果返回密码。 这仅对validation输入密码而不是再次检索密码非常有用。 我自己从来没有真正使用过这个,所以我无法帮助你。

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

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

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

请注意,现代/ metro应用程序没有这个问题,尽管它们仍然可以通过其他方式访问。

事实上,在桌面应用程序中存储密码是绝对不可能的。 但是 ,你可以接近100%。

关于您的原始方法 ,PasswordVault使用内置于Windows中的凭证锁定服务来安全地存储数据。 凭证储物柜绑定到用户的配置文件。 因此,通过PasswordVault存储数据基本上等同于保护数据的主密码方法,我将在下面详细讨论。 唯一不同的是,在这种情况下,主密码是用户的凭据。 这允许在用户会话期间运行的应用程序访问数据。

注意:为了清楚起见,我严格地谈论以允许您访问纯文本的方式存储它。 也就是说,将其存储在任何类型的加密数据库中,或者自己加密并在某处存储密文。 这种function在密码管理器等程序中是必需的,但在需要某种身份validation的程序中则不然。 如果这不是必需的,那么我强烈建议哈希密码,理想情况下按照zaph的答案中的说明 。 ( Thomas Pornin撰写的 这篇优秀文章中的更多信息)。


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

根据您实际尝试为每个程序实例存储的密码数量,您可能根本不必担心生成和安全存储密钥。 如果要存储多个密码,则只需要求用户输入一个主密码 ,对其执行一些salting和散列,并将结果用作所有其他密码的加密密钥。 在解密时,请让用户再次输入。 如果您要存储多个密码,那么我强烈建议您采用这种方法。 这是最安全的方法 。 然而,对于我的其余部分,我将假设这不是一个可行的选择。

首先,我强烈建议您不要为每次安装都使用相同的密钥。 根据安全生成的随机数据,为程序的每个实例创建一个新的实例。 根据有关系统的信息,通过在每次需要时动态生成密钥来抵制“避免必须存储密钥”的诱惑。 这和硬编码string superSecretKey = "12345";一样安全string superSecretKey = "12345"; 进入你的程序。 攻击者不会花很长时间来弄清楚这个过程。


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

一旦您有物理访问权限,没有什么是安全的

所以,理想情况下,没人会。 将加密密钥存储在正确安全的远程服务器上可以最大限度地减少攻击者恢复加密密钥的可能性。 已经写了关于服务器端安全性的全书,所以我不在这里讨论。

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

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


之前我说的不是简单地生成密钥就是因为,就像在代码中将其存储为变量一样,你完全依赖于混淆来保证密钥的安全。 关于这种方法的事情是它通常不会 。 但是,有时您没有其他选择。 输入白盒密码术 。

白盒密码术基本上是模糊处理。 即使在白盒方案中,它也是有效的,攻击者可以访问并修改字节码。 它是通过默默无闻的安全的缩影。 与仅仅持续隐藏( string superSecretKey代表string superSecretKey方法)或在需要时生成密钥string superSecretKey ,白盒密码术基本上依赖于在运行中生成密码本身

已经写好了整篇论文 ,很难完成正确的实施,你的里程可能会有所不同。 你应该只考虑这个,如果你真的真的想尽可能安全地做到这一点。


然而,混淆仍然是模糊处理。 所有它真正能做的就是减慢攻击者的速度。 我必须提供的最终解决方案可能看起来倒退,但它的工作原理是:不要以数字方式隐藏加密密钥。 实际隐藏它。 让用户在加密时插入USB驱动器,(安全地)生成随机密钥,然后将其写入USB驱动器。 然后,无论何时解密,用户只需将驱动器重新插入,程序就会读取该密钥。

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


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

唯一的替代方法是使用存储在代码中某处的私钥来加密密码。 (有人可以轻松地反汇编代码并获取密钥)然后将加密密码存储在PasswordVault中,但是唯一的安全性是任何应用程序都无法访问密码。

这是双重安全性,如果受到攻击的机器,攻击者可以访问PasswordVault但不能访问您的密码,因为他们需要一个私钥才能解密密码,并且会隐藏在代码中的某个位置。

为了使其更安全,如果您将私钥保留在服务器上并公开API以在存储到Vault之前加密和解密密码,则会使其最安全。 我认为这是人们转移到OAuth(在PasswordVault中存储OAuth令牌等)而不是将密码存储在Vault中的原因。

理想情况下,我建议不要存储密码,而是从服务器获取一些令牌并保存并使用该令牌进行身份validation。 并将该令牌存储在PasswordVault中。

通过各种加密和存储策略,始终可以推动安全性。 让事情变得更难只是让数据检索更长久,永远不可能。 因此,您需要考虑最合适的保护级别,考虑执行成本x时间(人力和机器)和开发成本x时间方面。

如果我严格考虑您的请求 ,我只需添加一个图层(类,接口)来加密您的密码。 最好采用非对称加密(而不是RSA)。 假设其他软件没有访问您的程序数据(程序,文件或进程),这就足够了。 您可以使用SSH.NET( https://github.com/sshnet/SSH.NET )快速实现此目的。

如果您想推动安全性并对二进制逆向工程(包括私钥检索)提供一定程度的保护,我建议使用一个小的(进程受限的)加密VM(如Docker, https://blogs.msdn。 microsoft.com/mvpawardprogram/2015/12/15/getting-started-with-net-and-docker/ )基于解决方案,如Denuvo( https://www.denuvo.com/ )。 加密对于每个客户和基于机器是唯一的。 你必须将c#program封装到ac / c ++程序(它就像一个容器)中,它将完成所有内存中的加密解密。

您可以实施自己的策略,具体取决于您需要的投资类型和保修。

如果你的程序是一个后端程序,你可以选择最好的策略(我唯一真正推荐的)是在客户端存储私钥,在后端存储公钥并进行本地解密,所有传输的密码都会因此加密。 我想说的是,密码和密钥实际上是实现相同目标的不同策略:检查程序是否在不知道个人身份的情况下与合适的人交谈; 我的意思是:不是存储密码,而是直接存储公钥。