7

How do I hash an users input(password) to database and then later read the hashed password during login?

I believe the solution is to hash the password upon register, where the password is saved as hashed inside db. Later upon Login, it should un-hash and compare its password with users password-input. But I don't know how to do it.

I allowed password to have nvarchar(MAX)in db since hashed password are usually long.

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

Register:

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

Login:

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

I'm using database first.

Ezony
  • 141
  • 1
  • 3
  • 9
  • 2
    You do **not** encrypt passwords. You hash them. –  Oct 01 '16 at 01:32
  • @StephenMuecke Thanks! I fixed it. – Ezony Oct 01 '16 at 01:36
  • 1
    Why are you not using Identity which will do this all out of the box? If you want do do all this manually, then refer [this blog](https://crackstation.net/hashing-security.htm) –  Oct 01 '16 at 01:38
  • Why did you posted same question twice? Have you looked at the answers here? http://stackoverflow.com/questions/39802862/mvc-how-to-hash-and-salt – Farukh Oct 01 '16 at 05:37
  • Just using a hash function is not sufficient and just adding a salt does little to improve the security. Instead iIterate over an HMAC with a random salt for about a 100ms duration and save the salt with the hash. Use functions such as `PBKDF2`, `password_hash`, `Bcrypt` and similar functions. The point is to make the attacker spend a lot of time finding passwords by brute force. – zaph Oct 01 '16 at 11:39

3 Answers3

19

You should never need to unhash a password. A cryptographic hash function is supposed to be a one-way operation.

(And that's precisely why it is called hashing and not encrypting. If unhashing passwords was to be a normal procedure in your flow of operations, then it would not be hashing and unhashing, it would be encrypting and decrypting. So, hashing is a different thing from encryption, precisely because unhashing is not supposed to ever happen.)

Hashing provides security, because nobody can steal your user's passwords even if they manage to view the contents of your database.

  • When the user registers, compute the hash of their password, store the hash in the database, and forget the password forever.

  • When the user logs in, compute the hash of the password they entered, (forget that password too,) and see if the hash matches the hash stored in the database.

This is the mechanism used by most websites out there, and that's precisely why if you successfully go through the "I forgot my password" procedure, they will still not show you your password: they don't have it; they cannot retrieve it even if they wanted to. Instead, they send you a password reset link.

As for how to compute a hash from a string, the interwebz abound with answers to that question, for example: MD5 (MSDN); SHA-256 (MSDN); SHA-512 (MSDN)

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • If i write "Password" and it get hashed and I wrote another another "Password", will they both have same hash-value then? Or are they getting random hash-value every time time? If randomly, then how is it possible to compare the password when user log in? If not randomly, is it possible to steal users hash-value and log in with it(somehow bypass/avoid hashing the stolen hashed-password)? – Ezony Oct 01 '16 at 02:10
  • 2
    @Ezony they would have the same hash every time. Great answer here Mike. – Jonesopolis Oct 01 '16 at 02:14
  • @Ezony they would have the same hash. That's why you create a salt which is just a string of random characters to tack on to the end. You then store the salt and hash. When they type the password you add the salt then hash it to see if it compares with the salted hash you have stored. Each password gets a different salt; therefore, all hashes are unique even if the password is the same. – tphx Oct 01 '16 at 02:15
  • @tphx Ah interesting. Is there any easy demonstration you know that I can follow? For hash and salt. – Ezony Oct 01 '16 at 02:35
  • MD5 is not considered safe anymore and can be cracked easily with modern PC's. Use at list SHA256 with HMAC. Generate randomly salt and store it somewhere. – Farukh Oct 01 '16 at 05:43
  • 1
    @Ezony If you are going to store passwords yourself, at least use a decent hashing algorithm like bcrypt. Not MD5. – juunas Oct 01 '16 at 06:34
  • @Ezony Here is a nice write-up on the InfoSec SE: [link](http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords) – juunas Oct 01 '16 at 06:36
  • Thanks everyone for the comments. As you might guess, I was not available to comment because I went to sleep. I agree MD5 is not particularly secure, but then again, I do not think that the task at hand has any particularly high security demands. – Mike Nakis Oct 01 '16 at 06:59
  • @MikeNakis If you are going to use MD5, why even bother, you will have essentially the same security as storing the plain passwords: none. It is the users that will suffer from poor password handling, they deserve, and expect, good security. – zaph Oct 01 '16 at 11:43
  • Here is why: an attacker hits your site, gets the MD5 passwords, use brute force with a table of common passwords and has the user's username and password. Not uses this on another site to gain access to more sensitive data since most users re-use passwords. You have just helped compromise the user. Note: On my laptop I can perform 3,000,000 MD5 hashes per second. Attacker will love your site and you will not even know it was successfuly attacked. – zaph Oct 01 '16 at 11:48
  • @zaph I know. But now someone has downvoted my answer because of this. So, it is now personal. – Mike Nakis Oct 01 '16 at 12:20
  • @MikeNakis "So, it is now personal.", what does that mean? We are here to provide good answers and when security is the issue good security. Using just MD5 to secure a password is not good security, not even close. If you know this as you acknowledge then update the answer. – zaph Oct 01 '16 at 13:14
  • Did anyone even saw my answer below? – Farukh Oct 02 '16 at 03:20
9

Use the System.Web.Helpers.Crypto NuGet package from Microsoft.

You hash a password like this: var hash = Crypto.HashPassword("foo");

You verify a password like this: var verified = Crypto.VerifyHashedPassword(hash, "foo");

Kai Hartmann
  • 3,106
  • 1
  • 31
  • 45
5

When it comes to security don't try to reinvent the wheel. Use Claims based authentication.

If you still must manage usernames and passwords use Hash-based message authentication code (HMAC)

I would also recommend investing sometime and reading Enterprise Security Best Practices. There are already smarter people who solved this problems why reinvent the wheel. And .NET has all the goodies there.

Example below:

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

NOTE: Salts do not have to be kept secret and can be stored alongside the hash itself. It's to increase security from rainbow table attack. Please don't post same question twice. Duplicate from here.

Travis J
  • 81,153
  • 41
  • 202
  • 273
Farukh
  • 2,173
  • 2
  • 23
  • 38