将密码格式从加密密码更改为散列密码

将密码格式从加密密码更改为散列密码

问题描述:

我发现令人惊讶的是,将现有数据库从加密密码密码转换为散列密码的信息很少。 (我能够找到更多有关转换另一种方式的信息,但这并没有多大帮助。)将密码格式从加密密码更改为散列密码

正如大多数人所知,更改web.config中的passwordFormat设置仅影响新用户。我有一个数百个用户的数据库,我想将它们转换为使用哈希密码而不更改这些现有密码。

是否有人熟悉如何接近这个?感谢您的任何提示。

这是我与我怎么看远了启动方法:

  1. 在我的web.config创建两个MembershipProviders,一个用于加密密码和一个用于散列。
  2. 使用加密密码提供程序遍历所有用户。 (SqlMembershipProvider.GetAllUsers
  3. 使用加密密码提供程序获取用户密码。 (MembershipUser.GetPassword
  4. 使用哈希密码提供程序将用户密码更改为相同密码。 (MembershipUser.ChangePassword

所以它会是这样的:

<membership defaultProvider="HashedProvider"> 
     <providers> 
      <clear /> 
      <add name="HashedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" /> 
      <add name="EncryptedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="true" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Encrypted" type="System.Web.Security.SqlMembershipProvider" /> 
     </providers> 
    </membership> 

代码:

SqlMembershipProvider hashedProvider = (SqlMembershipProvider)Membership.Providers["HashedProvider"]; 
SqlMembershipProvider encryptedProvider = (SqlMembershipProvider)Membership.Providers["EncryptedProvider"]; 

int unimportant; 
foreach (MembershipUser user in encryptedProvider.GetAllUsers(0, Int32.MaxValue, out unimportant)) 
{ 
    hashedProvider.ChangePassword(user.UserName, user.GetPassword(), user.GetPassword()); 
} 
+1

我正在尝试将明文密码更新为加密密码。我希望他们哈希,但客户端没有。总之,这个解决方案看起来很有前途非常优雅的简单。希望它有效。 – mikesigs 2011-02-10 15:36:19

我会告诫你不要随意散列你的密码,因为这种方法有很多警告。这Blog post about hashing passwords是非常有见识的,我认为你应该阅读它。为什么你想要散列密码而不是加密?

+3

感谢您的链接,这是一个有趣的阅读。也就是说,没有任何方法是100%安全的,哈希密码是当前密码存储的行业标准。为了方便用户使用加密密码(我可以通过电子邮件发送给他们),我建立了自己的网站,但是我收到了抱怨,这给我的用户带来了风险,尤其是当他们在多个网站上使用相同的密码时。 – 2011-02-09 18:41:30

出于安全原因,从数据库中的加密密码切换到散列绝对是正确的决定。

一般创建哈希出你现有的加密密码,你应该首先对它们进行解密,然后散列它们。请注意,您将会丢失(当您最终切换时)原始密码。相反,您将拥有用户密码的唯一指纹(散列)。

还考虑使用盐的散列(防御rainbow tables等),也有慢的哈希算法出于安全考虑,而不是快速的像MD5一个样子BCryptCodeplex & Article: How To Safely Store A Password)。

请记住,在未来将切换哈希算法比将其从ecryption更改为哈希更加费力。所以,你想这样做正确的第一次;)

+0

是的,我明白什么是散列密码,以及如何不能从散列转换为原始密码。而且我知道我需要解密已加密的密码,然后对它们进行哈希处理。我不知道的是,我可以如何以一种能够与ASP.NET成员身份协同工作的方式来处理所有记录。 (顺便说一下,ASP.NET成员资格中没有使用散列密码的盐吗?) – 2011-02-09 18:43:33

+1

ASP.NET成员资格的默认散列算法是SHA1,它们使用编码为Base64的salt。 – 2011-02-09 18:48:52

格雷格的解决方案是一个良好的开端,但它不会影响现有的用户。 SqlMembershipProvider通过在表中存储PasswordFormat(0 = clear,1 = Hashed,2 = Encrypted)和密码来保护现有的用户和密码。更改提供程序密码格式只影响对用户表的插入。为了将现有用户的密码转换为哈希,您必须更改每个条目的PasswordFormat参数。这是一个简单的方法来做到这一点:

void HashAllPasswords() 
{ 
    var clearProvider = Membership.Providers["SqlProvider_Clear"]; 
    var hashedProvider = Membership.Providers["SqlProvider_Hashed"]; 
    int dontCare; 
    if (clearProvider == null || hashedProvider == null) return; 
    var passwords = clearProvider.GetAllUsers(0, int.MaxValue, out dontCare) 
     .Cast<MembershipUser>().ToDictionary(u => u.UserName, u => u.GetPassword()); 

    using (var conn = new SqlConnection(
      ConfigurationManager.ConnectionStrings[0].ConnectionString)) 
    { 
     conn.Open(); 
     using (var cmd = new SqlCommand(
       "UPDATE [aspnet_Membership] SET [PasswordFormat]=1", conn)) 
      cmd.ExecuteNonQuery(); 
    } 

    foreach (var entry in passwords) 
    { 
     var resetPassword = hashedProvider.ResetPassword(entry.Key, null); 
     hashedProvider.ChangePassword(entry.Key, resetPassword, entry.Value); 
    } 
}