Kaydet (Commit) 5a541e2e authored tarafından Tim Graham's avatar Tim Graham

Fixed #26188 -- Documented how to wrap password hashers.

üst 33a4040d
......@@ -199,6 +199,89 @@ bcrypt rounds.
Passwords updates when changing the number of bcrypt rounds was added.
.. _wrapping-password-hashers:
Password upgrading without requiring a login
--------------------------------------------
If you have an existing database with an older, weak hash such as MD5 or SHA1,
you might want to upgrade those hashes yourself instead of waiting for the
upgrade to happen when a user logs in (which may never happen if a user doesn't
return to your site). In this case, you can use a "wrapped" password hasher.
For this example, we'll migrate a collection of SHA1 hashes to use
PDKDF2(SHA1(password)) and add the corresponding password hasher for checking
if a user entered the correct password on login. We assume we're using the
built-in ``User`` model and that our project has an ``accounts`` app. You can
modify the pattern to work with any algorithm or with a custom user model.
First, we'll add the custom hasher:
.. snippet::
:filename: accounts/hashers.py
from django.contrib.auth.hashers import (
PBKDF2PasswordHasher, SHA1PasswordHasher,
)
class PBKDF2WrappedSHA1PasswordHasher(PBKDF2PasswordHasher):
algorithm = 'pbkdf2_wrapped_sha1'
def encode_sha1_hash(self, sha1_hash, salt, iterations=None):
return super(PBKDF2WrappedSHA1PasswordHasher, self).encode(sha1_hash, salt, iterations)
def encode(self, password, salt, iterations=None):
_, _, sha1_hash = SHA1PasswordHasher().encode(password, salt).split('$', 2)
return self.encode_sha1_hash(sha1_hash, salt, iterations)
The data migration might look something like:
.. snippet::
:filename: accounts/migrations/0002_migrate_sha1_passwords.py
from django.db import migrations
from ..hashers import PBKDF2WrappedSHA1PasswordHasher
def forwards_func(apps, schema_editor):
User = apps.get_model('auth', 'User')
users = User.objects.filter(password__startswith='sha1$')
hasher = PBKDF2WrappedSHA1PasswordHasher()
for user in users:
algorithm, salt, sha1_hash = user.password.split('$', 2)
user.password = hasher.encode_sha1_hash(sha1_hash, salt)
user.save(update_fields=['password'])
class Migration(migrations.Migration):
dependencies = [
('accounts', '0001_initial'),
# replace this with the latest migration in contrib.auth
('auth', '####_migration_name'),
]
operations = [
migrations.RunPython(forwards_func),
]
Be aware that this migration will take on the order of several minutes for
several thousand users, depending on the speed of your hardware.
Finally, we'll add a :setting:`PASSWORD_HASHERS` setting:
.. snippet::
:filename: mysite/settings.py
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'accounts.hashers.PBKDF2WrappedSHA1PasswordHasher',
]
Include any other hashers that your site uses in this list.
.. _sha1: https://en.wikipedia.org/wiki/SHA1
.. _pbkdf2: https://en.wikipedia.org/wiki/PBKDF2
.. _nist: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment