Fixed CVE-2025-13473 -- Standardized timing of check_password() in mod_wsgi auth handler.

Refs CVE-2024-39329, #20760.

Thanks Stackered for the report, and Jacob Walls and Markus Holtermann
for the reviews.

Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
Jake Howard
2025-11-19 16:52:28 +00:00
committed by Jacob Walls
parent 72ae25a9c2
commit 3eb814e02a
5 changed files with 88 additions and 7 deletions

View File

@@ -1,4 +1,7 @@
from unittest import mock
from django.contrib.auth.handlers.modwsgi import check_password, groups_for_user
from django.contrib.auth.hashers import get_hasher
from django.contrib.auth.models import Group, User
from django.test import TransactionTestCase, override_settings
@@ -73,3 +76,28 @@ class ModWsgiHandlerTestCase(TransactionTestCase):
self.assertEqual(groups_for_user({}, "test"), [b"test_group"])
self.assertEqual(groups_for_user({}, "test1"), [])
def test_check_password_fake_runtime(self):
"""
Hasher is run once regardless of whether the user exists. Refs #20760.
"""
User.objects.create_user("test", "test@example.com", "test")
User.objects.create_user("inactive", "test@nono.com", "test", is_active=False)
User.objects.create_user("unusable", "test@nono.com")
hasher = get_hasher()
for username, password in [
("test", "test"),
("test", "wrong"),
("inactive", "test"),
("inactive", "wrong"),
("unusable", "test"),
("doesnotexist", "test"),
]:
with (
self.subTest(username=username, password=password),
mock.patch.object(hasher, "encode") as mock_make_password,
):
check_password({}, username, password)
mock_make_password.assert_called_once()