Bicheng
Bicheng

Reputation: 727

How to do password check with hash?

I am learning Flask through Miguel Grinberg's awesome tutorial. In that chapter, He suggests storing user's password hash rather than the password itself for security reasons. The functions been used are generate_password_hash, check_password_hash. But even if you call generate_password_hash with the same string, you can get different hash values :

enter image description here

>>> from werkzeug.security import generate_password_hash
>>> generate_password_hash('foo')
'pbkdf2:sha256:50000$E4Mg0BEy$c8db80b3ddefad78a93eaa47b22da5ce04adb969913b00545302cbf23501fdbb'
>>> generate_password_hash('foo')
'pbkdf2:sha256:50000$UCXVV09c$fe38b6099a0059957e283f2e4706fdbf01ef6e762b1070116df17867aa04e053'

Then how does the check_password_hash work if the same string can have as many hash values as it like?

Upvotes: 2

Views: 9752

Answers (2)

Eric Tsui
Eric Tsui

Reputation: 1924

Then how does the check_password_hash work if the same string can have as many > hash values as it like?

A simplified solution could be like this,

1)without salt

 user_id|  raw_password  |   hash_value  
  user1 |  'foo'         |  same_hashed_value      
  user2 |  'foo'         |  same_hashed_value
   

As you may have known, here the same password yields same hash value, which is vulnerable for dictionary attack. So we can add some random value(salt) to mitigate this kind of attack, like the following solution showed.

2)with salt

generate hash process:

  user_id | raw_password  |   password_with_salt  |  hash_value   
   user1  |      'foo'    |  'foo#salt123'        |  different_hash_1   
   user2  |      'foo'    |  'foo#saltABC'        |  different_hash_2   

In this case, hash_value and its related salt_value could be stored in the database. Otherwise, concat (hash_vaule, salt_value) as one string to store, which is equivalent.

check hash process:

1)Retrieve the user's salt_value and hash_value from the database.
2)Append the salt_value to the given password and hash it using the same hash function.
3)Compare the hash of the given password with the hash from the database. If they match, the password is correct. Otherwise, the password is incorrect.

Upvotes: 3

Sam
Sam

Reputation: 2200

Passwords are hashed with a salt, which is a pseudorandom string of letters and numbers. The salt will be different every time you run generate_password_hash(). Therefore, the resulting hash will be different as well.

This is done so that hackers cannot simply guess the hash of common passwords. For example the hash of 'pass1234' by itself would be the same every time. However, the hash of 'pass1234 + salt will be different each time. Your database should store the hash, as well as the salt (importantly not the plaintext password). This minimises the damage caused if information is leaked about user accounts.

In the case of Flask and werkzeug, the return value of generate_password_hash() is in the form: method$salt$hash (you can see the two $ symbols in the screenshot you provided). So next time you check the plaintext password against the hash, you has it with the salt value from generate_password_hash() and see if it matches the hash value.

Upvotes: 7

Related Questions