mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Fixed CVE-2016-2513 -- Fixed user enumeration timing attack during login.
This is a security fix.
This commit is contained in:
committed by
Tim Graham
parent
c5544d2892
commit
67b46ba701
@@ -10,9 +10,10 @@ from django.contrib.auth.hashers import (
|
||||
check_password, get_hasher, identify_hasher, is_password_usable,
|
||||
make_password,
|
||||
)
|
||||
from django.test import SimpleTestCase
|
||||
from django.test import SimpleTestCase, mock
|
||||
from django.test.utils import override_settings
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
try:
|
||||
import crypt
|
||||
@@ -214,6 +215,28 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||
finally:
|
||||
hasher.rounds = old_rounds
|
||||
|
||||
@skipUnless(bcrypt, "bcrypt not installed")
|
||||
def test_bcrypt_harden_runtime(self):
|
||||
hasher = get_hasher('bcrypt')
|
||||
self.assertEqual('bcrypt', hasher.algorithm)
|
||||
|
||||
with mock.patch.object(hasher, 'rounds', 4):
|
||||
encoded = make_password('letmein', hasher='bcrypt')
|
||||
|
||||
with mock.patch.object(hasher, 'rounds', 6), \
|
||||
mock.patch.object(hasher, 'encode', side_effect=hasher.encode):
|
||||
hasher.harden_runtime('wrong_password', encoded)
|
||||
|
||||
# Increasing rounds from 4 to 6 means an increase of 4 in workload,
|
||||
# therefore hardening should run 3 times to make the timing the
|
||||
# same (the original encode() call already ran once).
|
||||
self.assertEqual(hasher.encode.call_count, 3)
|
||||
|
||||
# Get the original salt (includes the original workload factor)
|
||||
algorithm, data = encoded.split('$', 1)
|
||||
expected_call = (('wrong_password', force_bytes(data[:29])),)
|
||||
self.assertEqual(hasher.encode.call_args_list, [expected_call] * 3)
|
||||
|
||||
def test_unusable(self):
|
||||
encoded = make_password(None)
|
||||
self.assertEqual(len(encoded), len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH)
|
||||
@@ -337,6 +360,25 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||
finally:
|
||||
hasher.iterations = old_iterations
|
||||
|
||||
def test_pbkdf2_harden_runtime(self):
|
||||
hasher = get_hasher('default')
|
||||
self.assertEqual('pbkdf2_sha256', hasher.algorithm)
|
||||
|
||||
with mock.patch.object(hasher, 'iterations', 1):
|
||||
encoded = make_password('letmein')
|
||||
|
||||
with mock.patch.object(hasher, 'iterations', 6), \
|
||||
mock.patch.object(hasher, 'encode', side_effect=hasher.encode):
|
||||
hasher.harden_runtime('wrong_password', encoded)
|
||||
|
||||
# Encode should get called once ...
|
||||
self.assertEqual(hasher.encode.call_count, 1)
|
||||
|
||||
# ... with the original salt and 5 iterations.
|
||||
algorithm, iterations, salt, hash = encoded.split('$', 3)
|
||||
expected_call = (('wrong_password', salt, 5),)
|
||||
self.assertEqual(hasher.encode.call_args, expected_call)
|
||||
|
||||
def test_pbkdf2_upgrade_new_hasher(self):
|
||||
hasher = get_hasher('default')
|
||||
self.assertEqual('pbkdf2_sha256', hasher.algorithm)
|
||||
@@ -365,6 +407,20 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||
self.assertTrue(check_password('letmein', encoded, setter))
|
||||
self.assertTrue(state['upgraded'])
|
||||
|
||||
def test_check_password_calls_harden_runtime(self):
|
||||
hasher = get_hasher('default')
|
||||
encoded = make_password('letmein')
|
||||
|
||||
with mock.patch.object(hasher, 'harden_runtime'), \
|
||||
mock.patch.object(hasher, 'must_update', return_value=True):
|
||||
# Correct password supplied, no hardening needed
|
||||
check_password('letmein', encoded)
|
||||
self.assertEqual(hasher.harden_runtime.call_count, 0)
|
||||
|
||||
# Wrong password supplied, hardening needed
|
||||
check_password('wrong_password', encoded)
|
||||
self.assertEqual(hasher.harden_runtime.call_count, 1)
|
||||
|
||||
def test_load_library_no_algorithm(self):
|
||||
with self.assertRaises(ValueError) as e:
|
||||
BasePasswordHasher()._load_library()
|
||||
|
||||
Reference in New Issue
Block a user