【问题标题】:Asp.net MVC - How to hash passwordAsp.net MVC - 如何散列密码
【发布时间】:2017-02-09 15:50:44
【问题描述】:

如何将用户输入(密码)散列到数据库,然后在登录期间读取散列密码?

我相信解决方案是在注册时对密码进行哈希处理,密码在数据库中保存为哈希值。稍后登录时,它应该取消哈希并将其密码与用户密码输入进行比较。 但我不知道该怎么做。

我允许密码有nvarchar(MAX)in db,因为散列密码通常很长。

        [Required]
        [StringLength(MAX, MinimumLength = 3, ErrorMessage = "min 3, max 50 letters")]
        public string Password { get; set; }

注册:

        [HttpPost]
        public ActionResult Register(User user) {
            if (ModelState.IsValid) {

                        var u = new User {
                            UserName = user.UserName,                               
                            Password = user.Password
                        };

                        db.Users.Add(u);
                        db.SaveChanges();

                    return RedirectToAction("Login");
                }
            }return View();    
        }

登录:

  public ActionResult Login() {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Login(User u) {
        if (ModelState.IsValid) 
        {
            using (UserEntities db = new UserEntities()) {

                //un-hash password?

                var v = db.Users.Where(a => a.UserName.Equals(u.UserName) && a.Password.Equals(u.Password)).FirstOrDefault();
                if (v != null) {

                    return RedirectToAction("Index", "Home"); //after login
                }
            }
        }return View(u);
    }

我先使用数据库。

【问题讨论】:

  • 加密密码。你散列它们。
  • @StephenMuecke 谢谢!我修好了。
  • 您为什么不使用开箱即用的 Identity?如果您想手动完成所有这些操作,请参考this blog
  • 您为什么两次发布相同的问题?你看过这里的答案吗? stackoverflow.com/questions/39802862/mvc-how-to-hash-and-salt
  • 仅使用散列函数是不够的,仅添加盐对提高安全性无济于事。相反,iIterate over an HMAC with a random salt for about 100ms duration and save the salt with the hash.使用PBKDF2password_hashBcrypt等函数和类似函数。关键是让攻击者花费大量时间通过蛮力寻找密码。

标签: c# asp.net-mvc entity-framework hash


【解决方案1】:

您永远不需要取消密码。 cryptographic hash function 应该是单向操作。

(这正是它被称为 hashing 而不是 encrypting 的原因。如果在您的操作流程中取消哈希密码是一个正常的过程,那么它就不会是散列和反散列,这将是加密和解密。因此,散列与加密是不同的,正是因为不应该发生散列。)

散列提供安全性,因为即使他们设法查看您的数据库内容,也没有人可以窃取您用户的密码。

  • 当用户注册时,计算其密码的哈希值,将哈希值存储在数据库中,然后永远忘记密码。

  • 当用户登录时,计算他们输入的密码的哈希值,(忘记密码,)并查看哈希值是否与存储在数据库中的哈希值匹配。

这是大多数网站使用的机制,这就是为什么如果您成功通过“我忘记了密码”程序,他们将仍然不会显示您的密码:他们不会没有它;即使他们想,他们也无法取回它。相反,他们会向您发送密码重置链接。

至于如何从字符串中计算哈希值,interwebz 上有很多关于该问题的答案,例如:MD5 (MSDN); SHA-256 (MSDN); SHA-512 (MSDN)

【讨论】:

  • 如果我写“密码”并且它被散列并且我写了另一个“密码”,那么它们会有相同的散列值吗?还是他们每次都获得随机哈希值?如果是随机的,那么用户登录时如何比较密码?如果不是随机的,是否有可能窃取用户哈希值并使用它登录(以某种方式绕过/避免哈希被盗的哈希密码)?
  • @Ezony 他们每次都会有相同的哈希值。很好的答案,迈克。
  • @Ezony 他们会有相同的哈希值。这就是为什么你创建一个盐,它只是一串随机字符,以附加到最后。然后存储盐和哈希。当他们输入密码时,您添加盐,然后对其进行哈希处理,以查看它是否与您存储的加盐哈希进行比较。每个密码都有不同的盐;因此,即使密码相同,所有哈希值也是唯一的。
  • @tphx 很有趣。你知道我可以遵循任何简单的演示吗?用于哈希和盐。
  • @Ezony 如果您要自己存储密码,至少要使用像 bcrypt 这样的散列算法。不是 MD5。
【解决方案2】:

使用来自 Microsoft 的 System.Web.Helpers.Crypto NuGet 包。

您可以像这样散列密码: var hash = Crypto.HashPassword("foo");

您验证这样的密码: var verified = Crypto.VerifyHashedPassword(hash, "foo");

【讨论】:

    【解决方案3】:

    在安全方面,不要试图重新发明轮子。使用基于Claims 的身份验证。

    如果您仍然必须管理用户名和密码,请使用基于哈希的消息验证码 (HMAC)

    我还建议投资一些时间并阅读Enterprise Security Best Practices。已经有更聪明的人解决了这个问题,为什么要重新发明轮子。 .NET 拥有所有的好东西。

    下面的例子:

    using System.Security.Cryptography;
    using System.Text;
    
    //--------------------MyHmac.cs-------------------
    public static class MyHmac
    {
        private const int SaltSize = 32;
    
        public static byte[] GenerateSalt()
        {
            using (var rng = new RNGCryptoServiceProvider())
            {
                var randomNumber = new byte[SaltSize];
    
                rng.GetBytes(randomNumber);
    
                return randomNumber;
    
            }
        }
    
        public static byte[] ComputeHMAC_SHA256(byte[] data, byte[] salt)
        {
            using (var hmac = new HMACSHA256(salt))
            {
                return hmac.ComputeHash(data);
            }
        }
    }
    
    
    
    //-------------------Program.cs---------------------------
    string orgMsg = "Original Message";
            string otherMsg = "Other Message";
    
    
            Console.WriteLine("HMAC SHA256 Demo in .NET");
    
            Console.WriteLine("----------------------");
            Console.WriteLine();
    
            var salt = MyHmac.GenerateSalt();
    
            var hmac1 = MyHmac.ComputeHMAC_SHA256(Encoding.UTF8.GetBytes(orgMsg), salt);
            var hmac2 = MyHmac.ComputeHMAC_SHA256(Encoding.UTF8.GetBytes(otherMsg), salt);
    
    
            Console.WriteLine("Original Message Hash:{0}", Convert.ToBase64String(hmac1));
            Console.WriteLine("Other Message Hash:{0}", Convert.ToBase64String(hmac2));
    

    注意:盐不必保密,可以与散列本身一起存储。这是为了增加对rainbow table 攻击的安全性。 请不要两次发布相同的问题。复制自here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-19
      • 2017-10-20
      • 2011-05-10
      • 2012-06-09
      • 2011-02-24
      • 2013-11-02
      • 1970-01-01
      • 2021-09-26
      相关资源
      最近更新 更多