Asp.net MVC -如何散列密码

本文关键字:何散列 密码 net MVC Asp | 更新日期: 2023-09-27 18:09:50

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

我认为解决方案是在注册时散列密码,其中密码保存为db内的散列。在登录之后,它应该解除散列并将其密码与用户的密码输入进行比较。但我不知道该怎么做。

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

        [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);
    }

Asp.net MVC -如何散列密码

永远都不需要对密码进行解列。加密散列函数应该是单向操作。

(这就是为什么它被称为哈希而不是加密。如果对密码进行散列是操作流中的一个正常过程,那么它就不是散列和散列,而是加密和解密。因此,散列与加密是不同的,正是因为散列不应该发生。)

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

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

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

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

关于如何从字符串中计算哈希,互联网上有很多答案,例如:MD5 (MSDN);sha - 256 (MSDN);sha - 512 (MSDN)

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

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

你像这样验证一个密码:var verified = Crypto.VerifyHashedPassword(hash, "foo");

当涉及到安全问题时,不要试图重新发明轮子。使用基于声明的身份验证

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

我还建议投资,并阅读企业安全最佳实践。已经有更聪明的人解决了这个问题,为什么要重新发明轮子呢?而且。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));

注意:盐不必保密,可以与哈希本身一起存储。这是为了防止彩虹桌的攻击。请不要重复发同样的问题。从这里复制