Fixed #29161 -- Removed BCryptPasswordHasher from PASSWORD_HASHERS.

This commit is contained in:
Tim Graham 2018-02-26 09:05:18 -05:00 committed by GitHub
parent c4fa0143f7
commit 5b589a47b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 20 additions and 31 deletions

View File

@ -512,7 +512,6 @@ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
AUTH_PASSWORD_VALIDATORS = [] AUTH_PASSWORD_VALIDATORS = []

View File

@ -2835,7 +2835,6 @@ Default::
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
.. setting:: AUTH_PASSWORD_VALIDATORS .. setting:: AUTH_PASSWORD_VALIDATORS

View File

@ -278,6 +278,23 @@ Dropped support for PostgreSQL 9.3
The end of upstream support for PostgreSQL 9.3 is September 2018. Django 2.1 The end of upstream support for PostgreSQL 9.3 is September 2018. Django 2.1
supports PostgreSQL 9.4 and higher. supports PostgreSQL 9.4 and higher.
Removed ``BCryptPasswordHasher`` from the default ``PASSWORD_HASHERS`` setting
------------------------------------------------------------------------------
If you used bcrypt with Django 1.4 or 1.5 (before ``BCryptSHA256PasswordHasher``
was added in Django 1.6), you might have some passwords that use the
``BCryptPasswordHasher`` hasher.
You can check if that's the case like this::
from django.contrib.auth import get_user_model
User = get_user_model()
User.objects.filter(password__startswith='bcrypt$$')
If you want to continue to allow those passwords to be used, you'll
have to define the :setting:`PASSWORD_HASHERS` setting (if you don't already)
and include ``'django.contrib.auth.hashers.BCryptPasswordHasher'``.
Miscellaneous Miscellaneous
------------- -------------

View File

@ -62,7 +62,6 @@ The default for :setting:`PASSWORD_HASHERS` is::
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
This means that Django will use PBKDF2_ to store all passwords but will support This means that Django will use PBKDF2_ to store all passwords but will support
@ -99,7 +98,6 @@ To use Argon2 as your default storage algorithm, do the following:
'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
Keep and/or add any entries in this list if you need Django to :ref:`upgrade Keep and/or add any entries in this list if you need Django to :ref:`upgrade
@ -126,7 +124,6 @@ To use Bcrypt as your default storage algorithm, do the following:
PASSWORD_HASHERS = [ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher',
@ -138,31 +135,6 @@ To use Bcrypt as your default storage algorithm, do the following:
That's it -- now your Django install will use Bcrypt as the default storage That's it -- now your Django install will use Bcrypt as the default storage
algorithm. algorithm.
.. admonition:: Password truncation with BCryptPasswordHasher
The designers of bcrypt truncate all passwords at 72 characters which means
that ``bcrypt(password_with_100_chars) == bcrypt(password_with_100_chars[:72])``.
The original ``BCryptPasswordHasher`` does not have any special handling and
thus is also subject to this hidden password length limit.
``BCryptSHA256PasswordHasher`` fixes this by first hashing the
password using sha256. This prevents the password truncation and so should
be preferred over the ``BCryptPasswordHasher``. The practical ramification
of this truncation is pretty marginal as the average user does not have a
password greater than 72 characters in length and even being truncated at 72
the compute powered required to brute force bcrypt in any useful amount of
time is still astronomical. Nonetheless, we recommend you use
``BCryptSHA256PasswordHasher`` anyway on the principle of "better safe than
sorry".
.. admonition:: Other bcrypt implementations
There are several other implementations that allow bcrypt to be
used with Django. Django's bcrypt support is NOT directly
compatible with these. To upgrade, you will need to modify the
hashes in your database to be in the form ``bcrypt$(raw bcrypt
output)``. For example:
``bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy``.
.. _increasing-password-algorithm-work-factor: .. _increasing-password-algorithm-work-factor:
Increasing the work factor Increasing the work factor
@ -202,7 +174,6 @@ default PBKDF2 algorithm:
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
] ]
That's it -- now your Django install will use more iterations when it That's it -- now your Django install will use more iterations when it

View File

@ -172,6 +172,7 @@ class TestUtilsHashPass(SimpleTestCase):
self.assertFalse(check_password(' ', blank_encoded)) self.assertFalse(check_password(' ', blank_encoded))
@skipUnless(bcrypt, "bcrypt not installed") @skipUnless(bcrypt, "bcrypt not installed")
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher'])
def test_bcrypt(self): def test_bcrypt(self):
encoded = make_password('lètmein', hasher='bcrypt') encoded = make_password('lètmein', hasher='bcrypt')
self.assertTrue(is_password_usable(encoded)) self.assertTrue(is_password_usable(encoded))
@ -187,6 +188,7 @@ class TestUtilsHashPass(SimpleTestCase):
self.assertFalse(check_password(' ', blank_encoded)) self.assertFalse(check_password(' ', blank_encoded))
@skipUnless(bcrypt, "bcrypt not installed") @skipUnless(bcrypt, "bcrypt not installed")
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher'])
def test_bcrypt_upgrade(self): def test_bcrypt_upgrade(self):
hasher = get_hasher('bcrypt') hasher = get_hasher('bcrypt')
self.assertEqual('bcrypt', hasher.algorithm) self.assertEqual('bcrypt', hasher.algorithm)
@ -219,6 +221,7 @@ class TestUtilsHashPass(SimpleTestCase):
hasher.rounds = old_rounds hasher.rounds = old_rounds
@skipUnless(bcrypt, "bcrypt not installed") @skipUnless(bcrypt, "bcrypt not installed")
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.BCryptPasswordHasher'])
def test_bcrypt_harden_runtime(self): def test_bcrypt_harden_runtime(self):
hasher = get_hasher('bcrypt') hasher = get_hasher('bcrypt')
self.assertEqual('bcrypt', hasher.algorithm) self.assertEqual('bcrypt', hasher.algorithm)