A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/django/django/commit/4d334bea06cac63dc1272abcec545b85136cca0e below:

[2.2.x] Fixed CVE-2019-19844 -- Used verified user email for password… · django/django@4d334be · GitHub

File tree Expand file treeCollapse file tree 4 files changed

+92

-8

lines changed

Filter options

Expand file treeCollapse file tree 4 files changed

+92

-8

lines changed Original file line number Diff line number Diff line change

@@ -20,6 +20,15 @@

20 20

UserModel = get_user_model()

21 21 22 22 23 +

def _unicode_ci_compare(s1, s2):

24 +

"""

25 +

Perform case-insensitive comparison of two identifiers, using the

26 +

recommended algorithm from Unicode Technical Report 36, section

27 +

2.11.2(B)(2).

28 +

"""

29 +

return unicodedata.normalize('NFKC', s1).casefold() == unicodedata.normalize('NFKC', s2).casefold()

30 + 31 + 23 32

class ReadOnlyPasswordHashWidget(forms.Widget):

24 33

template_name = 'auth/widgets/read_only_password_hash.html'

25 34

read_only = True

@@ -256,11 +265,16 @@ def get_users(self, email):

256 265

that prevent inactive users and users with unusable passwords from

257 266

resetting their password.

258 267

"""

268 +

email_field_name = UserModel.get_email_field_name()

259 269

active_users = UserModel._default_manager.filter(**{

260 -

'%s__iexact' % UserModel.get_email_field_name(): email,

270 +

'%s__iexact' % email_field_name: email,

261 271

'is_active': True,

262 272

})

263 -

return (u for u in active_users if u.has_usable_password())

273 +

return (

274 +

u for u in active_users

275 +

if u.has_usable_password() and

276 +

_unicode_ci_compare(email, getattr(u, email_field_name))

277 +

)

264 278 265 279

def save(self, domain_override=None,

266 280

subject_template_name='registration/password_reset_subject.txt',

@@ -273,15 +287,17 @@ def save(self, domain_override=None,

273 287

user.

274 288

"""

275 289

email = self.cleaned_data["email"]

290 +

email_field_name = UserModel.get_email_field_name()

276 291

for user in self.get_users(email):

277 292

if not domain_override:

278 293

current_site = get_current_site(request)

279 294

site_name = current_site.name

280 295

domain = current_site.domain

281 296

else:

282 297

site_name = domain = domain_override

298 +

user_email = getattr(user, email_field_name)

283 299

context = {

284 -

'email': email,

300 +

'email': user_email,

285 301

'domain': domain,

286 302

'site_name': site_name,

287 303

'uid': urlsafe_base64_encode(force_bytes(user.pk)),

@@ -292,7 +308,7 @@ def save(self, domain_override=None,

292 308

}

293 309

self.send_mail(

294 310

subject_template_name, email_template_name, context, from_email,

295 -

email, html_email_template_name=html_email_template_name,

311 +

user_email, html_email_template_name=html_email_template_name,

296 312

)

297 313 298 314 Original file line number Diff line number Diff line change

@@ -2,9 +2,25 @@

2 2

Django 1.11.27 release notes

3 3

============================

4 4 5 -

*Expected January 2, 2020*

5 +

*December 18, 2019*

6 6 7 -

Django 1.11.27 fixes a data loss bug in 1.11.26.

7 +

Django 1.11.27 fixes a security issue and a data loss bug in 1.11.26.

8 + 9 +

CVE-2019-19844: Potential account hijack via password reset form

10 +

================================================================

11 + 12 +

By submitting a suitably crafted email address making use of Unicode

13 +

characters, that compared equal to an existing user email when lower-cased for

14 +

comparison, an attacker could be sent a password reset token for the matched

15 +

account.

16 + 17 +

In order to avoid this vulnerability, password reset requests now compare the

18 +

submitted email using the stricter, recommended algorithm for case-insensitive

19 +

comparison of two identifiers from `Unicode Technical Report 36, section

20 +

2.11.2(B)(2)`__. Upon a match, the email containing the reset token will be

21 +

sent to the email address on record rather than the submitted address.

22 + 23 +

.. __: https://www.unicode.org/reports/tr36/#Recommendations_General

8 24 9 25

Bugfixes

10 26

========

Original file line number Diff line number Diff line change

@@ -2,9 +2,25 @@

2 2

Django 2.2.9 release notes

3 3

==========================

4 4 5 -

*Expected January 2, 2020*

5 +

*December 18, 2019*

6 6 7 -

Django 2.2.9 fixes a data loss bug in 2.2.8.

7 +

Django 2.2.9 fixes a security issue and a data loss bug in 2.2.8.

8 + 9 +

CVE-2019-19844: Potential account hijack via password reset form

10 +

================================================================

11 + 12 +

By submitting a suitably crafted email address making use of Unicode

13 +

characters, that compared equal to an existing user email when lower-cased for

14 +

comparison, an attacker could be sent a password reset token for the matched

15 +

account.

16 + 17 +

In order to avoid this vulnerability, password reset requests now compare the

18 +

submitted email using the stricter, recommended algorithm for case-insensitive

19 +

comparison of two identifiers from `Unicode Technical Report 36, section

20 +

2.11.2(B)(2)`__. Upon a match, the email containing the reset token will be

21 +

sent to the email address on record rather than the submitted address.

22 + 23 +

.. __: https://www.unicode.org/reports/tr36/#Recommendations_General

8 24 9 25

Bugfixes

10 26

========

Original file line number Diff line number Diff line change

@@ -754,6 +754,42 @@ def test_invalid_email(self):

754 754

self.assertFalse(form.is_valid())

755 755

self.assertEqual(form['email'].errors, [_('Enter a valid email address.')])

756 756 757 +

def test_user_email_unicode_collision(self):

758 +

User.objects.create_user('mike123', 'mike@example.org', 'test123')

759 +

User.objects.create_user('mike456', 'mıke@example.org', 'test123')

760 +

data = {'email': 'mıke@example.org'}

761 +

form = PasswordResetForm(data)

762 +

self.assertTrue(form.is_valid())

763 +

form.save()

764 +

self.assertEqual(len(mail.outbox), 1)

765 +

self.assertEqual(mail.outbox[0].to, ['mıke@example.org'])

766 + 767 +

def test_user_email_domain_unicode_collision(self):

768 +

User.objects.create_user('mike123', 'mike@ixample.org', 'test123')

769 +

User.objects.create_user('mike456', 'mike@ıxample.org', 'test123')

770 +

data = {'email': 'mike@ıxample.org'}

771 +

form = PasswordResetForm(data)

772 +

self.assertTrue(form.is_valid())

773 +

form.save()

774 +

self.assertEqual(len(mail.outbox), 1)

775 +

self.assertEqual(mail.outbox[0].to, ['mike@ıxample.org'])

776 + 777 +

def test_user_email_unicode_collision_nonexistent(self):

778 +

User.objects.create_user('mike123', 'mike@example.org', 'test123')

779 +

data = {'email': 'mıke@example.org'}

780 +

form = PasswordResetForm(data)

781 +

self.assertTrue(form.is_valid())

782 +

form.save()

783 +

self.assertEqual(len(mail.outbox), 0)

784 + 785 +

def test_user_email_domain_unicode_collision_nonexistent(self):

786 +

User.objects.create_user('mike123', 'mike@ixample.org', 'test123')

787 +

data = {'email': 'mike@ıxample.org'}

788 +

form = PasswordResetForm(data)

789 +

self.assertTrue(form.is_valid())

790 +

form.save()

791 +

self.assertEqual(len(mail.outbox), 0)

792 + 757 793

def test_nonexistent_email(self):

758 794

"""

759 795

Test nonexistent email address. This should not fail because it would

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4