3

What I am trying to do:

  • Create a database table of 2 most recently used passwords (not including current).

What have I discovered so far?

  • I have discovered the check_password('123') function
    • To my knowledge, this compares newly entered password to the current password before running User.set_password()
  • I have created a table to store a username with the two previously used (not including current) passwords.
  • I have discovered two different hash numbers
    • User.get_session_auth_hash()
      • Not sure if this is used for the password hashing?
    • User.set_password.hash()
      • Again, not sure if this is used for the password hashing?

My Issue:

In my python shell (under my project), I use User.set_password() and set the same current password after running User.password. Then when I run User.password again and see that there is a different hash.

How do I save the previous password hashing method and re-use it to re-hash the password in order to compare it to the previously hashed password??

Example of password hashing with the same password

u = User.objects.get(username='username')  # set user object
u.password  # display current hashed password (password is set to '123')
# pbkdf2_sha256$24000$2lTIbv4a3deG$ElefaaF0aaFh6y50ENNT2pCNQKpoNvYBQ1nZojz8sUg=
u.get_session_auth_hash()
# 8ad1d1d3ac6d442b241f79d447a01ef561960ea4
u.set_password.__hash__()
# -123 (not really, just not sure if safe to post)
u.set_password('123')
# pbkdf2_sha256$24000$VVnXSQdHAak4$FJv3SH/m9jkBcUXAuxJbm0wyhjI+3JHccF7+D2s4qvs=
u.get_session_auth_hash()
# 8416cf2da88c2905862a93464317d779cf938211
u.set_password.__hash__()
# -123 (has not changed after password change)

This is just me running my commands in the proposed shell. I can only imagine there's random salting going on with the hashing. Just figured this might be useful.

My research amongst this sight brought me to this post:

How to implement password change form in django 1.9

Research Update

I am assuming the session_auth_hash is being used in the hashing. I was starting to think maybe it was insecure to store this value in my database, but I can only assume that it is already stored somewhere because Django needs to use it to hash the entered password (when logging in) to verify it's the same password... I feel I just need to break down the set_password() function..

Final Thoughts

Are there potential security issues?

To possibly answer my own question: If storing the salt is a bad idea, then so would storing the hashed password from Django. If someone has gained access to my DB, they'll be able to find the salt from the hashed password already stored in the DB anyway. I don't see too much of a difference other than separating the salt for a would be attacker who could do it themselves.

Community
  • 1
  • 1
PythonReactor
  • 483
  • 4
  • 18

1 Answers1

2

Potential Breakthrough

When printing out your hashed password, this is the layout of it (as-per Django website): <algorithm>$<iterations>$<salt>$<hash>

Here is a hashed example (plain text pass is 123):

pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=

We can see that the algorithm used is pbjdf2 with a sha256 hash (the default for Django 1.9 (Other versions I'm sure, but have not personally confirmed). The iterations seems to be common amongst all attempts (24000, can someone confirm?) and the salt is clearly identifiable (tYZnlj3alG8Q in this case).

If I import from django.contrib.auth import hashers, I can run hashers.make_password('123', salt='tYZnlj3alG8Q') which prints out the same hash!

from django.contrib.auth import hashers
from django.contrib.auth.models import User
>>> u = User.objects.get(username='test')
>>> print u.password
pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=
>>> test = u.password
>>> test1 = hashers.make_password('123', salt='tYZnlj3alG8Q')
>>> print test1
pbkdf2_sha256$24000$tYZnlj3alG8Q$DuDmimgvgwFjiRT2B42/4oeMbNkKA/DVTCFXPte3Yic=
# an extra confirmation
>>> test == test1
True

I plan to set my table up as such:

ID --- username --- prev1 --- salt1 --- prev2 --- salt2

1  --- test     --- 123   --- ewew@ --- 321   --- saqd!

2  --- test1    --- 456   --- kaka% --- 654   --- ji;l(

Logic behind testing will be similar to

def old_pass_check():
    old_pass_1 = "prev1 pulled from DB"
    salt_1 = "salt1 pulled from DB"
    old_pass_2 = "prev2 pulled from DB
    salt_2 = "salt2 pulled from DB
    new_pass = "entered_pass"

    old_hash_1 = hashers.make_password('new_pass', salt=salt_1)
    old_hash_2 = hashers.make_password('new_pass', salt=salt_2)
    new_hash_1 = hashers.make_password('new_pass', salt=salt_1)
    new_hash_2 = hashers.make_password('new_pass', salt=salt_2)

    if new_hash_1 in {old_hash_1, old_hash_2}:
        return error
    elif new_hash_2 in {old_hash_1, old_hash_2}:
        return error

    else:
        set_password(new_pass)
        *logic to update latest used password and salt into DB table
         making sure only 2 latest passwords are there*
PythonReactor
  • 483
  • 4
  • 18