Ticket #27518: password_reset_security_issue_2.txt

File password_reset_security_issue_2.txt, 4.1 KB (added by Romain Garrigues, 8 years ago)

Solution 1 - redirect without token in the url

Line 
1diff --git a/django/contrib/auth/urls.py b/django/contrib/auth/urls.py
2index 233eef8..d4e5d4b 100644
3--- a/django/contrib/auth/urls.py
4+++ b/django/contrib/auth/urls.py
5@@ -15,6 +15,8 @@ urlpatterns = [
6
7 url(r'^password_reset/$', views.PasswordResetView.as_view(), name='password_reset'),
8 url(r'^password_reset/done/$', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
9+ url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/$',
10+ views.password_reset_confirm_secure, name='password_reset_confirm_secure'),
11 url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
12 views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
13 url(r'^reset/done/$', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
14diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
15index b84fae8..2117af2 100644
16--- a/django/contrib/auth/views.py
17+++ b/django/contrib/auth/views.py
18@@ -14,7 +14,7 @@ from django.contrib.auth.forms import (
19 from django.contrib.auth.tokens import default_token_generator
20 from django.contrib.sites.shortcuts import get_current_site
21 from django.http import HttpResponseRedirect, QueryDict
22-from django.shortcuts import resolve_url
23+from django.shortcuts import resolve_url, redirect
24 from django.template.response import TemplateResponse
25 from django.urls import reverse, reverse_lazy
26 from django.utils.decorators import method_decorator
27@@ -314,13 +314,49 @@ def password_reset_confirm(request, uidb64=None, token=None,
28 post_reset_redirect=None,
29 extra_context=None):
30 """
31+ Redirect to the real password reset view to not contain anymore the token in
32+ the url.
33+ """
34+ assert uidb64 is not None and token is not None # checked by URLconf
35+ request.session['internal-reset-token'] = token
36+ request.session['password_reset_parameters'] = dict(
37+ template_name=template_name,
38+ token_generator=token_generator,
39+ set_password_form=set_password_form,
40+ post_reset_redirect=post_reset_redirect,
41+ extra_context=extra_context,
42+ )
43+ return redirect('password_reset_confirm_secure', uidb64=uidb64)
44+
45+
46+# Doesn't need csrf_protect since no-one can guess the URL
47+@sensitive_post_parameters()
48+@never_cache
49+@deprecate_current_app
50+def password_reset_confirm_secure(request, uidb64=None,
51+ template_name='registration/password_reset_confirm.html',
52+ token_generator=default_token_generator,
53+ set_password_form=SetPasswordForm,
54+ post_reset_redirect=None,
55+ extra_context=None):
56+ """
57 View that checks the hash in a password reset link and presents a
58 form for entering a new password.
59 """
60 warnings.warn("The password_reset_confirm() view is superseded by the "
61 "class-based PasswordResetConfirmView().",
62 RemovedInDjango21Warning, stacklevel=2)
63+
64+ password_reset_parameters = request.session.get('password_reset_parameters')
65+ if password_reset_parameters:
66+ template_name = password_reset_parameters['template_name']
67+ token_generator = password_reset_parameters['token_generator']
68+ set_password_form = password_reset_parameters['set_password_form']
69+ post_reset_redirect = password_reset_parameters['post_reset_redirect']
70+ extra_context = password_reset_parameters['extra_context']
71+
72 UserModel = get_user_model()
73+ token = request.session.get('internal-reset-token')
74 assert uidb64 is not None and token is not None # checked by URLconf
75 if post_reset_redirect is None:
76 post_reset_redirect = reverse('password_reset_complete')
77@@ -344,6 +380,7 @@ def password_reset_confirm(request, uidb64=None, token=None,
78 else:
79 form = set_password_form(user)
80 else:
81+ del request.session['internal-reset-token']
82 validlink = False
83 form = None
84 title = _('Password reset unsuccessful')
Back to Top