c# - 我的 MVC3 密码处理是否足够

标签 c# asp.net-mvc encryption passwords

我已经阅读了大量关于如何存储和比较输入的密码的文章,有些是旧的,有些是新的,但都不同。因此,我采取了我认为最好的选择并实现了以下措施。

请注意,我创建了自己的身份验证提供程序,我既没有使用也没有继承自标准的 MS MembershipProvider(过于臃肿)。这是针对不需要“ super 安全”的轻量级站点,但我想遵循最佳实践。我只是想验证一下我没有做任何明显的错误或打开安全漏洞。此外,我查看了每个用户的密码加盐,但它似乎对我的需求来说过于复杂。这是一个有效的假设吗?

首先,我将以下 appSettings 键放入我的 web.config 中,它由我的 configurationProvider 类返回。

<add key="PasswordEncryptionKey" value="qTnY9lf...40 more random characters here" />

这是我的代码,它公开验证用户并私下检查存储的密码与输入的内容以及编码密码保存时。我没有显示添加或更新密码方法,因为它们使用相同的私有(private)方法。

public bool Authenticate(string emailAddress, string password, bool setAuthCookie = false)
{
  bool isAuthenticated = false;
  var member = _memberRepository.Find(m => m.Email == emailAddress).SingleOrDefault();
  if (member != null)
  {
    if (CheckPassword(password, member.Password))
    {
      isAuthenticated = true;
      FormsAuthentication.SetAuthCookie(emailAddress, setAuthCookie);
    }
  }
  return isAuthenticated;
}

private bool CheckPassword(string providedPassword, string storedPassword)
{
  return EncodePassword(providedPassword) == storedPassword;
}

private string EncodePassword(string password)
{
  var hash = new HMACSHA1
               {
                 Key = Encoding.ASCII.GetBytes(_configurationProvider.PasswordEncryptionKey)
               };
  string encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
  return encodedPassword;
}

我唯一的规则是:

  • 密码必须在数据库中异步加密,不可解密。
  • 该方法应该对字典或其他攻击具有合理的安全性(我不是在开发 FDIC 保险网站,只是一个基本的内部网)

有了这个,我有什么明显的遗漏吗?

最佳答案

我相信你的方案已经足够了,但还可以再改进一点。

在我看来,您已经开始使用 app.config 文件中的 EncryptionKey 进行加盐方案。然而,为了获得最佳安全实践,通常人们对每个密码使用不同的盐,并将盐与哈希一起存储在数据库中。

class MyAuthClass {
  private const int SaltSize = 40;
  private ThreadLocal<HashAlgorithm> Hasher;

  public MyAuthClass ()
  {
    // This is 'ThreadLocal' so your methods which use this are thread-safe.
    Hasher = new ThreadLocal<HashAlgorithm>( 
      () => new HMACSHA256(Encoding.ASCII.GetBytes(_configurationProvider.PasswordEncryptionKey)
    );
  } 

  public User CreateUser(string email, string password) {
    var rng = new RNGCryptoServiceProvider();
    var pwBytes = Encoding.Unicode.GetBytes(password);
    var salt = new byte[SaltSize];
    rng.GetBytes(salt);

    var hasher = Hasher.Value;
    hasher.TransformBlock(salt, 0, SaltSize, salt, 0);
    hasher.TransformFinalBlock(pwBytes, 0, pwBytes.Length);
    var finalHash = hasher.Hash;
    return new User { UserName = email, PasswordHash = finalHash, Salt = salt };
  }

使用这样的方案,您的密码会变得更加复杂,因为如果攻击者碰巧获得了哈希值,他还必须在暴力攻击期间猜测盐值。

这与配置文件中的 EncodingKey 的原理相同,但更安全,因为每个散列都有自己的盐。检查输入的密码是类似的:

  public bool IsPasswordCorrect(User u, string attempt) 
  {
    var hasher = Hasher.Value;
    var pwBytes = Encoding.Unicode.GetBytes(attempt);
    hasher.TransformBlock(u.Salt, 0, u.Salt.Length, Salt, 0);
    hasher.TransformFinalBlock(pwBytes, 0, pwBytes.Length);
    // LINQ method that checks element equality.
    return hasher.Hash.SequenceEqual(u.PasswordHash);  
  }
} // end MyAuthClass

当然,如果您更愿意将散列存储为字符串而不是字节数组,欢迎您这样做。

只需我的 2 美分!

关于c# - 我的 MVC3 密码处理是否足够,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9796419/

相关文章:

c# - 无法读取隐藏字段

mysql - 已经有一个与此连接关联的打开的 DataReader,必须先关闭它 + asp.net mvc

asp.net-mvc - 如何在版本信息中包含静态内容

android - 加密 - 整个文件或单个字段?

java - 解码自定义加密文件

c# - C++ 和 C# 之间的通信?

c# - Nlog - 为日志文件生成 header 部分

c# - 检查文件是否已在源代码管理中

asp.net-mvc - MVC 5 来自网页

asp.net - Web 服务开发从哪里开始?