1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[3.2.x] Fixed CVE-2023-46695 -- Fixed potential DoS in UsernameField on Windows.

Thanks MProgrammer (https://hackerone.com/mprogrammer) for the report.
This commit is contained in:
Mariusz Felisiak 2023-10-17 11:48:32 +02:00
parent e6d2591d9e
commit f9a7fb8466
3 changed files with 27 additions and 3 deletions

View File

@ -62,7 +62,15 @@ class ReadOnlyPasswordHashField(forms.Field):
class UsernameField(forms.CharField):
def to_python(self, value):
return unicodedata.normalize('NFKC', super().to_python(value))
value = super().to_python(value)
if self.max_length is not None and len(value) > self.max_length:
# Normalization can increase the string length (e.g.
# "ff" -> "ff", "½" -> "12") but cannot reduce it, so there is no
# point in normalizing invalid data. Moreover, Unicode
# normalization is very slow on Windows and can be a DoS attack
# vector.
return value
return unicodedata.normalize("NFKC", value)
def widget_attrs(self, widget):
return {

View File

@ -6,4 +6,14 @@ Django 3.2.23 release notes
Django 3.2.23 fixes a security issue with severity "moderate" in 3.2.22.
...
CVE-2023-46695: Potential denial of service vulnerability in ``UsernameField`` on Windows
=========================================================================================
The :func:`NFKC normalization <python:unicodedata.normalize>` is slow on
Windows. As a consequence, ``django.contrib.auth.forms.UsernameField`` was
subject to a potential denial of service attack via certain inputs with a very
large number of Unicode characters.
In order to avoid the vulnerability, invalid values longer than
``UsernameField.max_length`` are no longer normalized, since they cannot pass
validation anyway.

View File

@ -5,7 +5,7 @@ from unittest import mock
from django.contrib.auth.forms import (
AdminPasswordChangeForm, AuthenticationForm, PasswordChangeForm,
PasswordResetForm, ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget,
SetPasswordForm, UserChangeForm, UserCreationForm,
SetPasswordForm, UserChangeForm, UserCreationForm, UsernameField,
)
from django.contrib.auth.models import User
from django.contrib.auth.signals import user_login_failed
@ -132,6 +132,12 @@ class UserCreationFormTest(TestDataMixin, TestCase):
self.assertNotEqual(user.username, ohm_username)
self.assertEqual(user.username, 'testΩ') # U+03A9 GREEK CAPITAL LETTER OMEGA
def test_invalid_username_no_normalize(self):
field = UsernameField(max_length=254)
# Usernames are not normalized if they are too long.
self.assertEqual(field.to_python("½" * 255), "½" * 255)
self.assertEqual(field.to_python("" * 254), "ff" * 254)
def test_duplicate_normalized_unicode(self):
"""
To prevent almost identical usernames, visually identical but differing