【问题标题】:Convert ASP.NET Membership Passwords from Encrypted to Hashed将 ASP.NET 成员密码从加密转换为散列
【发布时间】:2011-04-27 02:20:04
【问题描述】:

我开发了一个使用 ASP.NET 成员资格的网站。根据以前网站的 cmets,我决定对密码进行加密,以便忘记密码的用户可以恢复。

但是,新网站(现在有超过 500 名注册用户)给我带来了一些批评,认为行业标准实际上是对密码进行哈希处理。

但是,经过相当广泛的搜索,我找不到任何关于如何将现有用户的密码从加密转换为散列的信息。

我知道我可以更改 web.config 文件,新用户的密码将使用新格式。但它不会更新现有用户。

注意:我之前问过一个类似的问题,但大多只是争论哪个更好,加密或散列。我已经结束了那次讨论,但我一直无法找到一种方法来转换它们而不会失去数百名已经注册的用户。

【问题讨论】:

    标签: asp.net asp.net-membership password-protection


    【解决方案1】:

    您似乎已经知道如何解密密码和更改 web.config 文件,但您对如何实施其余过程感到困惑。

    使用ILSpy,以下是为每个用户生成盐的方法:

    byte[] array = new byte[16];
    new RNGCryptoServiceProvider().GetBytes(array);
    return Convert.ToBase64String(array);    
    

    一旦你有了盐,下面是如何生成密码:

    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] array = Convert.FromBase64String(salt);
    byte[] array2 = new byte[array.Length + bytes.Length];
    Buffer.BlockCopy(array, 0, array2, 0, array.Length);
    Buffer.BlockCopy(bytes, 0, array2, array.Length, bytes.Length);   
    using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) {
      return Convert.ToBase64String(sha1.ComputeHash(array2));
    }
    

    其中passyou计算出来的纯文本密码,salt是上面第一个代码sn-p中计算出来的字符串。 default algorithm is SHA1,如果您想知道为什么要使用它。

    因为这是一个一次性的过程,所以我会编写一个 HTTP 处理程序来在一个短的、预定的维护期间手动更新数据库 - 希望你有这个奢侈。 (显然先备份和测试)。您需要更新aspnet_Membership 表中的以下字段:

    1. Password - 以上计算
    2. PasswordFormat - 1
    3. PasswordSalt - 以上计算

    从来没有做过这样的事情,但希望这会让你开始:)

    【讨论】:

    • 酷。我不能马上做到这一点,但看起来是一个好的开始。 (顺便说一句,很高兴听到有关 ILSpy 的消息。我们现在需要这个,因为 Red Gate 已经收购了 .NET Reflector!)
    • 其实 Red Gate 很久以前就收购了 .NET Reflector,一切都还好——直到他们decided to get nasty
    • 是的,我知道。但从那以后,该产品的使用变得越来越痛苦。
    【解决方案2】:

    恕我直言,Greg 对您之前的问题 (Changing passwordFormat from Encrypted to Hashed) 的回复(以及相关的 cmets)是可行的方法。本质上,您想要:

    1. 添加散列会员提供者
    2. 遍历所有加密密码的用户,
    3. 为每一个解密密码,创建哈希值,存储它,从数据库中删除加密版本,然后继续。

    完成后,应将所有加密密码用户转换为散列。

    【讨论】:

    • 你看到我对格雷格的最后评论了吗?我基本上通过了他的建议,但最后,我显然遗漏了一些东西。不幸的是,他没有回应那条评论,就这样结束了。我想我对 ASP.NET 成员的不了解已经够多了,以至于我无法做到这一点。
    • 当您说“存储它”时,这是什么意思?通过会员提供商还是直接?我不清楚如何在不丢失现有数据的情况下做到这一点。您如何兼顾多个提供者并指定哪个提供者做什么?
    • 这个想法是您想要丢失现有数据(加密密码)。根据上一篇文章中的 cmets,您需要使用 MembershipUser.GetPassword() 从加密的提供者那里获取当前密码。这是可能的,因为您使用的是可逆加密 - 该方法不适用于散列提供程序)。一旦你有解密的密码,你想要散列它(用盐)。这是一个单向过程。然后,您使用散列成员提供程序存储密码的结果散列(有效地用散列覆盖加密密码)。 (续)
    • 然后您使用新的散列提供程序对所有用户进行身份验证。散列提供者通过获取用户提供的密码、使用用于散列原始(存储的)密码的相同算法对其进行散列并比较两个散列来对用户进行身份验证。如果用户在登录时输入的密码与他们在设置帐户时使用的密码相匹配,则生成的哈希值将匹配。如果有人闯入您的数据库,他们就没有您的用户密码。他们只有哈希值,这(希望)不会对他们有多大好处。有关散列的更多信息,请参阅:bit.ly/dlRWpc
    • 好吧,我将其视为转换现有数据而不是丢失它。 :-) 我现在被困在另一个项目上,但我会尽可能详细地检查你的 cmets。感谢您提供更多信息。
    【解决方案3】:

    也许我在这里遗漏了一些东西,但它应该很简单。创建一个解密密码的过程,然后相应地加盐并将加盐的哈希值+用户的解密密码存储在数据库中。显然,您不想散列用户的加密密码。也不要忘记储存盐。

    【讨论】:

    • 澄清一下,你应该把盐放在密码的末尾,而不是之前,当你散列它时。我相信 ASP.NET Auth 默认使用 SHA1。
    • 我从概念上知道需要做什么。我想关于 ASP.NET 成员资格的情况已经够多了,我还不清楚一些细节。
    • (我只是在为“加密”值输入乱码)。用户“kappasims”,密码“test”。加密密码:83@#!s34。解密密码“测试”。解密 83@#!s34 以获得“测试”。生成随机盐:“12345”。然后连接成“test12345”。使用 SHA1 将“test12345”散列为“!@83104234!@#$@#”。将“!@83104234!@#$@#”存储为哈希,将“12345”存储为盐。泡沫。冲洗。重复。
    猜你喜欢
    • 2013-11-02
    • 2014-01-09
    • 2011-06-24
    • 2011-09-08
    • 2011-02-26
    • 2011-02-18
    • 2011-04-28
    • 1970-01-01
    • 2011-06-23
    相关资源
    最近更新 更多