我想在我的桌面应用程序(基于WPF)中使用Windows.Security.Credentials.PasswordVault来安全地存储用户的密码。我设法使用此MSDN article访问此Windows 10 API。
我做了一些实验,看来从一个桌面应用程序(不是原生UWP应用程序)写入PasswordVault的任何数据都可以从任何其他桌面应用程序中读取。即使使用Desktop Bridge技术打包我的桌面应用程序,因此拥有程序包标识也无法修复此漏洞。
任何想法如何解决这个问题,并能够安全地存储应用程序的数据?
更新:似乎PasswordVault没有为DPAPI添加额外的安全性。案件结案,结果为否定。
答案 0 :(得分:4)
(这是我对你的帖子所能理解的)
使用这些API时,没有真正的方法可以防止桌面应用之间的数据访问http://www.hanselman.com/blog/SavingAndRetrievingBrowserAndOtherPasswords.aspx更多地了解它。您可能只是想解密您的信息。
内存访问限制很困难,用户执行的代码总是可由用户检索,因此很难对此进行限制。
您是否考虑过使用Windows Data Protection API: https://msdn.microsoft.com/en-us/library/ms995355.aspx
从源头直接抓住 DPAPI是一项易于使用的服务,它将使必须为敏感应用程序数据提供保护的开发人员受益,例如密码和私钥
WDPAPI使用操作系统和Triple DES生成的密钥来加密/解密您的数据。这意味着您的应用程序不必生成这些密钥,这总是很好。
您还可以使用Rfc2898DeriveBytes类,它使用伪随机数生成器来解密您的密码。它比大多数解密器更安全,因为没有实际的方法可以从结果返回密码。这仅对验证输入密码而不是再次检索密码非常有用。我自己从来没有真正使用过这个,所以我无法帮助你。
另见这篇文章,提供了一个比我更好的解释方法。 How to securely save username/password (local)?
如果我以某种方式误解了这个问题,请告诉我,我会尝试更新答案。
请注意,现代/都市应用程序没有这个问题,尽管它们仍然可以通过其他方式访问。
答案 1 :(得分:4)
事实上,在桌面应用程序中存储密码是绝对不可能的。 然而,你可以接近100%。
关于原始方法,PasswordVault使用内置于Windows中的Credential Locker服务来安全地存储数据。凭证储物柜绑定到用户的配置文件。因此,通过PasswordVault存储数据基本上等同于主密码保护数据的方法,我将在下面详细讨论。唯一不同的是,在这种情况下,主密码是用户的凭证。这允许在用户会话期间运行的应用程序访问数据。
注意:为了清楚起见,我严格地谈论以允许您访问纯文本的方式存储它。也就是说,将其存储在任何类型的加密数据库中,或者自己加密并在某处存储密文。这种功能在密码管理器等程序中是必需的,但在需要某种身份验证的程序中则不然。如果不是必需品,那么我强烈建议您使用哈希密码,最好按照this zaph回答this所述的说明进行操作。 (Thomas Pornin精彩帖子Hardware Security Module)中的更多信息。
如果 是必需品,事情会变得复杂一些:如果你想阻止其他程序(或我认为的用户)能够查看明文密码,那么你唯一真正的选择是加密它。将密文存储在PasswordVault中是可选的,因为如果您使用良好的加密,您唯一的弱点就是有人发现您的密钥。因此,密文本身可以存储在任何地方。这让我们了解了关键。
根据您实际尝试为每个程序实例存储的密码数量,您可能不必担心在所有中生成并安全存储密钥。如果要存储多个密码,则只需要求用户输入一个主密码,对其执行一些salting和散列,并将结果用作所有其他密码的加密密钥。在解密时,请让用户再次输入。如果您要存储多个密码,那么我强烈建议您采用这种方法。它是最安全的方法。然而,对于我的其余部分,我将假设这不是一个可行的选择。
首先,我强烈建议你不为每次安装都使用相同的密钥。根据安全生成的随机数据,为程序的每个实例创建一个新的实例。抵制诱惑,避免必须存放密钥"通过在每次需要时根据系统信息生成它。这与将string superSecretKey = "12345";
硬编码到程序中一样安全。它不会让攻击者长时间去弄清楚这个过程。
现在,存储它是真正棘手的部分。信息安全的一般规则如下:
物理访问后,没有什么是安全的
所以,理想情况下,没人会。将加密密钥存储在正确安全的远程服务器上可以最大限度地减少攻击者恢复加密密钥的可能性。已经写了关于服务器端安全性的全书,所以我不会在这里讨论。
另一个好的选择是使用HSM(this)。这些漂亮的小设备是为这项工作而打造的。访问存储在HSM中的密钥几乎是不可能的。但是,只有在您确定每台用户的计算机都具有其中之一时(例如在企业环境中),此选项才可行。
.Net通过配置系统提供各种解决方案。您可以将密钥存储在app.config
的加密部分中。这通常用于保护连接字符串。关于如何做到这一点有很多资源。我推荐White Box cryptography精彩的博客文章,它会告诉你大部分你需要知道的内容。
我之前说过的原因不是简单地生成密钥就是因为,就像在代码中将其存储为变量一样,您完全依赖于混淆来保证其安全。关于这种方法的事情是通常不会。但是,有时您没有其他选择。输入papers。
白盒加密基本上是模糊处理。即使在白盒方案中,它也是有效的,攻击者都可以访问并修改字节码。它是通过默默无闻的安全的缩影。与仅仅持续隐藏(infosec代表string superSecretKey
方法)或在需要时生成密钥相反,白盒加密基本上依赖于动态生成密码。
已经写了整个{{3}},很难完成正确的实施,你的里程可能会有所不同。你应该只考虑这个,如果你真的 真的想要尽可能安全地做到这一点。
然而,混淆仍然是模糊处理。所有它真正能做的就是减慢攻击者的速度。我必须提供的最终解决方案可能看起来倒退,但它的工作原理是:不要以数字方式隐藏加密密钥。隐藏物理。让用户在加密时插入USB驱动器,(安全地)生成随机密钥,然后将其写入USB驱动器。然后,无论何时解密,用户只需将驱动器重新插入,程序就会读取该密钥。这有点类似于主密码方法,因为它让用户保持密钥安全。但是,它有一些显着的优点。例如,此方法允许大量加密密钥。一个只能容纳1兆字节文件的密钥可以花费数十亿甚至几十年的时间来通过蛮力攻击来破解。此外,如果密钥被发现,用户只能责怪自己。
总结,看看您是否可以避免存储加密密钥。如果您不能,请不惜一切代价避免将其存储在本地。否则,你唯一的选择就是让黑客尽可能难以理解。无论你如何选择这样做,都要确保每个密钥都不同,所以即使攻击者确实找到了一个密钥,其他用户也是如此。钥匙是安全的。
答案 2 :(得分:2)
唯一的替代方法是使用存储在代码中某处的私钥加密密码。 (有人可以轻松地反汇编代码并获取密钥)然后将加密密码存储在PasswordVault中,但是唯一的安全性是任何应用程序都无法访问密码。
这是双重安全性,如果机器受到攻击,攻击者可以访问PasswordVault但不能访问您的密码,因为他们需要一个私钥来解密密码,并且会隐藏在代码中的某个位置。
为了使其更安全,如果您将私钥留在服务器上并公开API以在存储到Vault之前加密和解密密码,则会使其最安全。我认为这是人们转移到OAuth(在PasswordVault中存储OAuth令牌等)而不是在密码库中存储密码的原因。
理想情况下,我建议不要存储密码,而是从服务器获取一些令牌并保存并使用该令牌进行身份验证。并将该令牌存储在PasswordVault中。
答案 3 :(得分:2)
始终可以通过各种加密和存储策略来推动安全性。做出更难的事情只会使数据检索更长,永远不可能。因此,您需要考虑最合适的保护级别,考虑执行成本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#程序封装到一个c / c ++程序(它就像一个容器),它将完成所有内存中的加密解密。
您可以根据所需的投资和保修类型实施自己的策略。
如果您的程序是后端程序,您可以选择最好的策略(我真正推荐的唯一策略),即在客户端存储私钥,在后端存储公钥并进行本地解密,所有因此传输的密码将被加密。我想说的是,密码和密钥实际上是实现相同目标的不同策略:检查程序是否在不知道个人身份的情况下与合适的人交谈;我的意思是:不是存储密码,而是直接存储公钥。