ASP.NET Identity密码哈希处理

36

新的ASP.net身份验证项目带来了一些有用的代码和接口,用于网站安全。要实现使用这些接口的自定义系统(而不是使用包含在MVC 5模板中的标准Entity Framework实现),需要一个IPasswordHasher

IPasswordHasher 接口在 ASP.net 身份验证中的作用

namespace Microsoft.AspNet.Identity
{
    public interface IPasswordHasher
    {
         string HashPassword(string password);
         PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword);
    }
}

在ASP.net Identity中,是否可能使用密码哈希加盐的方式进行更安全的加密,并通过此接口实现?


8
在传递密码之前,请对其进行加盐处理。 - James
提供的密码字符串 providedPassword 是否也需要进行哈希处理? - Djeroen
虽然它们提供了使用自己的哈希函数的方法,但强烈不建议这样做。此外,默认的哈希函数已经对密码进行了盐处理,否则对相同的密码进行两次哈希将会得到类似的结果。 - Ioanna
3个回答

60

健康警告: 了解您使用的ASP.Net Identity版本。如果是来自Github存储库的新版本之一,则应直接参考源代码。

我写这篇文章时,当前版本(3.0.0-rc1/.../PasswordHasher.cs)的密码处理程序与下面的答案显著不同。这个更新版本支持多个哈希算法版本,并且被记录为(并且在您阅读此文时可能会进一步改变):

版本2:

  • PBKDF2使用HMAC-SHA1,128位盐,256位子密钥,1000次迭代。
  • (另请参阅:SDL加密指南v5.1,第III部分)
  • 格式:{ 0x00, salt, subkey }

版本3:

  • PBKDF2使用HMAC-SHA256,128位盐,256位子密钥,10000次迭代。
  • 格式:{ 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
  • (所有UInt32都以big-endian方式存储。)

原始答案仍然适用于原始版本的ASP.Net Identity,如下所示:


@jd4u是正确的,但为了更详细地解释一下,这不能在他的答案中进行评论:

因此,如果您要使用 Rfc2898DeriveBytes,只需使用 PasswordHasher - 所有繁重的工作已经完成 (希望正确)。

详细信息

目前 PasswordHasher 使用的完整代码非常接近于:

int saltSize = 16;
int bytesRequired = 32;
byte[] array = new byte[1 + saltSize + bytesRequired];
int iterations = SOME; // 1000, afaik, which is the min recommended for Rfc2898DeriveBytes
using (var pbkdf2 = new Rfc2898DeriveBytes(password, saltSize, iterations))
{
    byte[] salt = pbkdf2.Salt;        
    Buffer.BlockCopy(salt, 0, array, 1, saltSize);
    byte[] bytes = pbkdf2.GetBytes(bytesRequired);
    Buffer.BlockCopy(bytes, 0, array, saltSize+1, bytesRequired);
}
return Convert.ToBase64String(array);

谢谢!我需要一个新的方法来创建我的哈希密码,与用户管理器分开,这个方法完美地解决了我的问题。 - Steven Combs
1
这是我迄今为止找到的最有用的解释,框架上嵌入了默认哈希器,因此当我保存用户时,只需执行以下操作:var hash = new PasswordHasher().HashPassword(userViewModel.Password); var userAggregate = UserAggregate.Create(userViewModel.Username, userViewModel.Email, hash, DateTime.Now.ToString()); - Raffaeu
  1. 使用32字节输出的PBKDF2-HMAC-SHA1是一个不好的想法。输出超过本机大小(20字节)会使防御者减速2倍,而攻击者则完全不会减速。
  2. 1000次迭代有点低。
- CodesInChaos
2
这是当前的样子 https://github.com/aspnet/Identity/blob/37d4e2b6ff3e64985f0fa7017108b164dce9233b/src/Microsoft.AspNet.Identity/PasswordHasher.cs它已经与上述描述有所不同 https://github.com/aspnet/Identity/commit/37d4e2b6ff3e64985f0fa7017108b164dce9233b - Guy
所以,如果我正确地阅读了这个答案(和源代码),AspNet.Identity 2.0 的默认密码哈希器使用了1,000次迭代的PBKDF2-HMACSHA1。这是开箱即用的,我什么也不需要做。一旦我升级到Core,它将使用版本3,该版本使用10,000次迭代的HMACSHA256。看起来你还可以选择你想要的版本2或3,并且你可以通过PasswordHasher选项构造函数设置迭代次数。有人可以为我确认一下吗? - fujiiface
显示剩余2条评论

34
“在ASP.net Identity中,是否可以使用密码加盐来进行更安全的加密?”
是的,该接口已为Core框架中已存在的PasswordHasher的新实现提供。
还请注意,默认实现已经使用了Salt+Bytes。
创建自定义PasswordHasher(例如MyPasswordHasher)后,您可以将其分配给UserManager实例,例如userManager.PasswordHasher=new MyPasswordHasher()。 查看一个这样的IPasswordHasher示例 “要实现使用接口的自定义系统(而不是使用MVC 5模板中包含的标准Entity Framework实现),需要IPasswordHasher。”
要从EF实现替代系统, - 您应该实现所有核心接口。 - 不需要实现IPasswordHasher。 PasswordHasher已作为其实现在Core框架中提供。

9

在从Membership更新到AspNet.Identity时,我遇到了一个问题。Rfc2898哈希值与以前使用的哈希值不同。这是有充分理由的,但更改哈希值将要求所有用户重置密码。为了解决这个问题,这个自定义实现使其向后兼容:

public class MyPasswordHasher : PasswordHasher {

   public FormsAuthPasswordFormat FormsAuthPasswordFormat { get; set; }

   public MyPasswordHasher(FormsAuthPasswordFormat format) {
      FormsAuthPasswordFormat = format;
   }

   public override string HashPassword(string password) {
      return FormsAuthentication.HashPasswordForStoringInConfigFile(password, FormsAuthPasswordFormat.ToString());
   }

   public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) {
     var testHash = FormsAuthentication.HashPasswordForStoringInConfigFile(providedPassword, FormsAuthPasswordFormat.ToString());
     return hashedPassword.Equals(testHash) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
   }
}

当你创建了UserManager实例后,只需设置哈希器:

Usermanager.PasswordHasher = new MyPasswordHasher(FormsAuthPasswordFormat.SHA1);

代码抱怨HashPasswordForStoringInConfigFile方法已经过时,但这没关系,因为我们知道整个过程就是为了摆脱旧技术。


太好了。我也有同样的问题,即我想将成千上万的用户从Membership提供程序迁移到新的ASP.Identity。我会尝试一下。 - agarcian
这基本上也是我最终所做的。我想指出你的构造函数名称不正确(应该是MyPasswordHasher(...))。对于我的实现,我还在登录时更新用户密码,以使用新的哈希功能,使用了这里的一些示例:http://www.asp.net/identity/overview/migrations/migrating-an-existing-website-from-sql-membership-to-aspnet-identity - trnelson
我已经修复了复制和粘贴错误。 - Joerg Krause
我正在尝试做同样的事情,但没有成功。VerifyHashedPassword方法的第一个参数是指向数据库表AspNetUsers列PasswordHash,对吗?我应该从旧成员资格列中放什么到这个列中?只有密码还是密码和盐一起? - Ammar Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接