Asp.net MVC - 如何哈希密码

Ezo*_*ony 5 c# asp.net-mvc hash entity-framework

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

我相信解决方案是在注册时散列密码,其中密码在db中保存为散列.登录后,它应该取消哈希并将其密码与用户密码输入进行比较.但我不知道该怎么做.

我允许密码nvarchar(MAX)在db中,因为哈希密码通常很长.

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

寄存器:

        [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();    
        }
Run Code Online (Sandbox Code Playgroud)

登录:

  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);
    }
Run Code Online (Sandbox Code Playgroud)

我先使用数据库.

Mik*_*kis 15

您永远不需要取消密码.一个加密散列函数应该是一个单向操作.

(这就是为什么它被称为散列而不是加密.如果在你的操作流程中使用密码是一个正常的过程,那么它就不会散列和散乱,它会加密和解密.所以,散列是一个不同的来自加密的东西,正是因为不应该发生不发生的事情.)

散列提供安全性,因为即使用户设法查看数据库的内容,也无法窃取用户的密码.

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

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

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

至于如何从字符串计算哈希值,interwebz对该问题的答案比比皆是,例如:MD5(MSDN) ; SHA-256(MSDN) ; SHA-512(MSDN)

  • @Ezony 他们每次都会有相同的哈希值。很好的答案,迈克。 (2认同)

Kai*_*ann 6

使用System.Web.Helpers.CryptoMicrosoft的NuGet 包。

你像这样散列一个密码: var hash = Crypto.HashPassword("foo");

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


Far*_*ukh 5

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

如果您仍然必须管理用户名和密码,请使用基于哈希的消息身份验证代码 ( 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));
Run Code Online (Sandbox Code Playgroud)

注意:盐不必保密,可以与哈希本身一起存储。这是为了提高彩虹表攻击的安全性。请不要将同一问题发布两次。从这里复制。