+76
-5
lines changedFilter options
+76
-5
lines changed Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1
+
from django.core.exceptions import SuspiciousOperation
2
+
3
+
4
+
class DisallowedModelAdminToField(SuspiciousOperation):
5
+
"""Invalid to_field was passed to admin view via URL query string"""
6
+
pass
Original file line number Diff line number Diff line change
@@ -275,6 +275,24 @@ def lookup_allowed(self, lookup, value):
275
275
clean_lookup = LOOKUP_SEP.join(parts)
276
276
return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
277
277
278
+
def to_field_allowed(self, request, to_field):
279
+
opts = self.model._meta
280
+
281
+
try:
282
+
field = opts.get_field(to_field)
283
+
except FieldDoesNotExist:
284
+
return False
285
+
286
+
# Make sure at least one of the models registered for this site
287
+
# references this field.
288
+
registered_models = self.admin_site._registry
289
+
for related_object in opts.get_all_related_objects():
290
+
if (related_object.model in registered_models and
291
+
field == related_object.field.rel.get_related_field()):
292
+
return True
293
+
294
+
return False
295
+
278
296
def has_add_permission(self, request):
279
297
"""
280
298
Returns True if the given request has permission to add an object.
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
12
12
from django.utils.http import urlencode
13
13
14
14
from django.contrib.admin import FieldListFilter
15
+
from django.contrib.admin.exceptions import DisallowedModelAdminToField
15
16
from django.contrib.admin.options import IncorrectLookupParameters
16
17
from django.contrib.admin.util import (quote, get_fields_from_path,
17
18
lookup_needs_distinct, prepare_lookup_value)
@@ -58,7 +59,10 @@ def __init__(self, request, model, list_display, list_display_links,
58
59
self.page_num = 0
59
60
self.show_all = ALL_VAR in request.GET
60
61
self.is_popup = IS_POPUP_VAR in request.GET
61
-
self.to_field = request.GET.get(TO_FIELD_VAR)
62
+
to_field = request.GET.get(TO_FIELD_VAR)
63
+
if to_field and not model_admin.to_field_allowed(request, to_field):
64
+
raise DisallowedModelAdminToField("The field %s cannot be referenced." % to_field)
65
+
self.to_field = to_field
62
66
self.params = dict(request.GET.items())
63
67
if PAGE_VAR in self.params:
64
68
del self.params[PAGE_VAR]
Original file line number Diff line number Diff line change
@@ -47,3 +47,18 @@ and the ``RemoteUserBackend``, a change to the ``REMOTE_USER`` header between
47
47
requests without an intervening logout could result in the prior user's session
48
48
being co-opted by the subsequent user. The middleware now logs the user out on
49
49
a failed login attempt.
50
+
51
+
Data leakage via query string manipulation in ``contrib.admin``
52
+
===============================================================
53
+
54
+
In older versions of Django it was possible to reveal any field's data by
55
+
modifying the "popup" and "to_field" parameters of the query string on an admin
56
+
change form page. For example, requesting a URL like
57
+
``/admin/auth/user/?pop=1&t=password`` and viewing the page's HTML allowed
58
+
viewing the password hash of each user. While the admin requires users to have
59
+
permissions to view the change form pages in the first place, this could leak
60
+
data if you rely on users having access to view only certain fields on a model.
61
+
62
+
To address the issue, an exception will now be raised if a ``to_field`` value
63
+
that isn't a related field to a model that has been registered with the admin
64
+
is specified.
Original file line number Diff line number Diff line change
@@ -47,3 +47,18 @@ and the ``RemoteUserBackend``, a change to the ``REMOTE_USER`` header between
47
47
requests without an intervening logout could result in the prior user's session
48
48
being co-opted by the subsequent user. The middleware now logs the user out on
49
49
a failed login attempt.
50
+
51
+
Data leakage via query string manipulation in ``contrib.admin``
52
+
===============================================================
53
+
54
+
In older versions of Django it was possible to reveal any field's data by
55
+
modifying the "popup" and "to_field" parameters of the query string on an admin
56
+
change form page. For example, requesting a URL like
57
+
``/admin/auth/user/?pop=1&t=password`` and viewing the page's HTML allowed
58
+
viewing the password hash of each user. While the admin requires users to have
59
+
permissions to view the change form pages in the first place, this could leak
60
+
data if you rely on users having access to view only certain fields on a model.
61
+
62
+
To address the issue, an exception will now be raised if a ``to_field`` value
63
+
that isn't a related field to a model that has been registered with the admin
64
+
is specified.
Original file line number Diff line number Diff line change
@@ -16,11 +16,12 @@
16
16
from django.core.urlresolvers import reverse
17
17
# Register auth models with the admin.
18
18
from django.contrib import admin
19
+
from django.contrib.admin.exceptions import DisallowedModelAdminToField
19
20
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
20
21
from django.contrib.admin.models import LogEntry, DELETION
21
22
from django.contrib.admin.sites import LOGIN_FORM_KEY
22
23
from django.contrib.admin.util import quote
23
-
from django.contrib.admin.views.main import IS_POPUP_VAR
24
+
from django.contrib.admin.views.main import IS_POPUP_VAR, TO_FIELD_VAR
24
25
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
25
26
from django.contrib.auth import REDIRECT_FIELD_NAME
26
27
from django.contrib.auth.models import Group, User, Permission, UNUSABLE_PASSWORD
@@ -557,6 +558,19 @@ def test_disallowed_filtering(self):
557
558
response = self.client.get("/test_admin/admin/admin_views/workhour/?employee__person_ptr__exact=%d" % e1.pk)
558
559
self.assertEqual(response.status_code, 200)
559
560
561
+
def test_disallowed_to_field(self):
562
+
with self.assertRaises(DisallowedModelAdminToField):
563
+
response = self.client.get("/test_admin/admin/admin_views/section/", {TO_FIELD_VAR: 'missing_field'})
564
+
565
+
# Specifying a field that is not refered by any other model registered
566
+
# to this admin site should raise an exception.
567
+
with self.assertRaises(DisallowedModelAdminToField):
568
+
response = self.client.get("/test_admin/admin/admin_views/section/", {TO_FIELD_VAR: 'name'})
569
+
570
+
# Specifying a field referenced by another model should be allowed.
571
+
response = self.client.get("/test_admin/admin/admin_views/section/", {TO_FIELD_VAR: 'id'})
572
+
self.assertEqual(response.status_code, 200)
573
+
560
574
def test_allowed_filtering_15103(self):
561
575
"""
562
576
Regressions test for ticket 15103 - filtering on fields defined in a
@@ -2138,10 +2152,9 @@ def test_with_fk_to_field(self):
2138
2152
"""Ensure that the to_field GET parameter is preserved when a search
2139
2153
is performed. Refs #10918.
2140
2154
"""
2141
-
from django.contrib.admin.views.main import TO_FIELD_VAR
2142
-
response = self.client.get('/test_admin/admin/auth/user/?q=joe&%s=username' % TO_FIELD_VAR)
2155
+
response = self.client.get('/test_admin/admin/auth/user/?q=joe&%s=id' % TO_FIELD_VAR)
2143
2156
self.assertContains(response, "\n1 user\n")
2144
-
self.assertContains(response, '<input type="hidden" name="t" value="username"/>', html=True)
2157
+
self.assertContains(response, '<input type="hidden" name="%s" value="id"/>' % TO_FIELD_VAR, html=True)
2145
2158
2146
2159
def test_exact_matches(self):
2147
2160
response = self.client.get('/test_admin/admin/admin_views/recommendation/?q=bar')
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