A RetroSearch Logo

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

Search Query:

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

Fixed a security issue related to password resets · django/django@b45c377 · GitHub

File tree Expand file treeCollapse file tree 4 files changed

+46

-1

lines changed

Filter options

Expand file treeCollapse file tree 4 files changed

+46

-1

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

@@ -19,6 +19,7 @@ def remote_user_auth_view(request):

19 19

(r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')),

20 20

(r'^remote_user/$', remote_user_auth_view),

21 21

(r'^password_reset_from_email/$', 'django.contrib.auth.views.password_reset', dict(from_email='staffmember@example.com')),

22 +

(r'^admin_password_reset/$', 'django.contrib.auth.views.password_reset', dict(is_admin_site=True)),

22 23

(r'^login_required/$', login_required(password_reset)),

23 24

(r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')),

24 25

)

Original file line number Diff line number Diff line change

@@ -9,6 +9,7 @@

9 9

from django.contrib.auth.models import User

10 10

from django.test import TestCase

11 11

from django.core import mail

12 +

from django.core.exceptions import SuspiciousOperation

12 13

from django.core.urlresolvers import reverse

13 14

from django.http import QueryDict

14 15

@@ -69,6 +70,44 @@ def test_email_found_custom_from(self):

69 70

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

70 71

self.assertEqual("staffmember@example.com", mail.outbox[0].from_email)

71 72 73 +

def test_admin_reset(self):

74 +

"If the reset view is marked as being for admin, the HTTP_HOST header is used for a domain override."

75 +

response = self.client.post('/admin_password_reset/',

76 +

{'email': 'staffmember@example.com'},

77 +

HTTP_HOST='adminsite.com'

78 +

)

79 +

self.assertEqual(response.status_code, 302)

80 +

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

81 +

self.assertTrue("http://adminsite.com" in mail.outbox[0].body)

82 +

self.assertEqual(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)

83 + 84 +

def test_poisoned_http_host(self):

85 +

"Poisoned HTTP_HOST headers can't be used for reset emails"

86 +

# This attack is based on the way browsers handle URLs. The colon

87 +

# should be used to separate the port, but if the URL contains an @,

88 +

# the colon is interpreted as part of a username for login purposes,

89 +

# making 'evil.com' the request domain. Since HTTP_HOST is used to

90 +

# produce a meaningful reset URL, we need to be certain that the

91 +

# HTTP_HOST header isn't poisoned. This is done as a check when get_host()

92 +

# is invoked, but we check here as a practical consequence.

93 +

def test_host_poisoning():

94 +

self.client.post('/password_reset/',

95 +

{'email': 'staffmember@example.com'},

96 +

HTTP_HOST='www.example:dr.frankenstein@evil.tld'

97 +

)

98 +

self.assertRaises(SuspiciousOperation, test_host_poisoning)

99 +

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

100 + 101 +

def test_poisoned_http_host_admin_site(self):

102 +

"Poisoned HTTP_HOST headers can't be used for reset emails on admin views"

103 +

def test_host_poisoning():

104 +

self.client.post('/admin_password_reset/',

105 +

{'email': 'staffmember@example.com'},

106 +

HTTP_HOST='www.example:dr.frankenstein@evil.tld'

107 +

)

108 +

self.assertRaises(SuspiciousOperation, test_host_poisoning)

109 +

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

110 + 72 111

def _test_confirm_start(self):

73 112

# Start by creating the email

74 113

response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})

Original file line number Diff line number Diff line change

@@ -151,7 +151,7 @@ def password_reset(request, is_admin_site=False,

151 151

'request': request,

152 152

}

153 153

if is_admin_site:

154 -

opts = dict(opts, domain_override=request.META['HTTP_HOST'])

154 +

opts = dict(opts, domain_override=request.get_host())

155 155

form.save(**opts)

156 156

return HttpResponseRedirect(post_reset_redirect)

157 157

else:

Original file line number Diff line number Diff line change

@@ -165,6 +165,11 @@ def get_host(self):

165 165

server_port = str(self.META['SERVER_PORT'])

166 166

if server_port != (self.is_secure() and '443' or '80'):

167 167

host = '%s:%s' % (host, server_port)

168 + 169 +

# Disallow potentially poisoned hostnames.

170 +

if set(';/?@&=+$,').intersection(host):

171 +

raise SuspiciousOperation('Invalid HTTP_HOST header: %s' % host)

172 + 168 173

return host

169 174 170 175

def get_full_path(self):

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