我应该如何存储用户名/密码以进行自动身份验证?

时间:2011-04-08 17:29:06

标签: asp.net database security authentication

我工作的组织有一些他们每天使用的不同网站。我被要求开发一个Web应用程序(使用ASP.NET),它可以访问/合成这些信息并将其显示在一个位置。不幸的是,其中一个网站不支持OAuth或类似的东西,因此我需要将他们的登录凭据存储在数据库中。

我的第一个想法是使用他们的站点凭据作为加密远程站点凭据的密钥。例如:Bob使用密码hunter2登录我的网站。使用该密码,我解密了Bob的www.example.com凭据并以Bob身份登录。由于除非Bob在我的网站上,否则我不需要访问example.com,因此我可以在完成后丢弃解密的凭据。

我的假设只是简单地使用hunter2(或任何Bob的密码)是不够的,并且有一种“标准”方式,我无法在Google或Stack Overflow上找到。

3 个答案:

答案 0 :(得分:1)

如果您无法避免在服务器上存储密码,那么使用用户的“主”密码(例如“hunter2”)进行加密是您最好的选择。在服务器受到威胁的情况下,没有其他方法可以提供保护。现在......你得到多少保护完全取决于用户主密码的复杂性。我将在最后提供我对该方案安全性的分析,但在此之前,让我回顾一下需要避免的陷阱。

首先 - 我假设您已经知道这一点,但是 - you must not store the user's master password anywhere。好的,假设不在......

请勿使用用户的实际密码作为加密功能的密钥。

如果您这样做,请考虑一下:如果攻击者设法下载整个用户表,并使用加密的 example.com 密码,该怎么办?我们都知道用户选择的密码很容易猜到。什么会阻止攻击者反复解密加密的 example.com 密码,尝试40 million commonly used passwords作为密钥,丢弃任何看起来不像密码的结果(即解密结果)没有出现在wordlist中)? AES是designed to be fast。虽然不是苹果与苹果的比较,但是如果您认为上述500mb字列表的加密版本可以在现代硬件上在大约一秒钟内解密,则应该传达AES的速度感。更糟糕的是,攻击者不仅会获得 example.com 密码,还会将密钥用于加密,换句话说,就是用户的主密码!

简而言之,这就是你需要使用key derivation function(KDF)的原因。 KDF将以三种方式为您提供理想的保护:

  1. 需要非常重要的时间来计算每个密钥。用户可以等待一秒钟以使服务器将其密码转换为密钥。攻击者可能不太愿意等待40,000,000秒 - 请参阅下面的分析。
  2. Salt密码。如果没有salt,攻击者可以一次性强制整个用户表,更不用说制作space-time tradeoff
  3. 即使攻击者恢复加密密钥,也可以防止恢复主密码。
  4. 提供所有三个的一个这样的KDF是PBKDF2。方便的是,.NET内置了an implementation

    public static byte[] DeriveKey(int keyBitSize, string password, byte[] salt) {
        const int iterations = 1<<12; // Once set, any change will break decryption.
        using (var kdf = new Rfc2898DeriveBytes(password, salt, iterations)) {
            return kdf.GetBytes(keyBitSize);
        }
    }
    

    <强>分析

    4000万秒不到500天。由于单词列表通常首先使用最常用的密码进行排序,因此攻击者很有可能找到密码的时间远远少于尝试整个单词表所用时间的一半。作为最后的皱纹,可以并行尝试密钥:500个节点的僵尸网络可以在一天内尝试整个词汇表。

    这是依赖用户密码加密安全性的问题。您可以选择接受此风险,也可以决定不在服务器上存储用户密码。如果您决定在服务器上存储加密密码,则可以通过提高用户主密码的复杂性要求来降低风险。

答案 1 :(得分:0)

无论你采取什么方法,都会遇到让你自己怀疑的问题。您需要根据您的环境平衡解决方案。看看最合适的是什么。

您应用的每个用户都会在远程系统上拥有一个帐户吗?用户如何通过系统进行身份验证?您的应用是否会在受信任的环境(例如公司网络)中运行。

我在一个内部系统上写了一个类似的应用程序,它有自己的用户名&amp;密码。我的应用程序使用Windows Integrated auth来确定用户是谁。然后它要求他们输入远程系统的密码。使用硬编码密钥加密该值将值存储在DB中。然后它可以检索该值,并对其进行解密。在需要时将其提供给远程系统。

现在在一个不受信任的环境中,有人可以获得我的二进制文件&amp;弄清楚他们的关键是什么&amp;获取所有密码。那会很糟糕。但是在公司网络上,如果他们这样做,他们应该来和为我工作。

答案 2 :(得分:0)

您已经可以访问用户的明文二级密码,因此无论您是否丢弃加密密钥,当您处于明确状态时,您仍然要对其安全负责。处理密码时请记住这一点。

如果您使用用户自己的密码进行加密,则会将所有辅助密码的强度降低到主要密码的强度。这可能是不好的,因为a)用户密码已经非常弱(我知道,为什么我们甚至在第一时间打扰?)和b)即使拥有最强的密码,它仍然无法与强大随机的强度相匹配256位AES密钥。

我的建议是考虑使用一个AES密钥加密其明文二级密码。然后,保护AES密钥。可能有意义的是,使用根AES密钥加密许多子密钥,每个用户一个。我想你必须进行风险分析。