Commit 2a446c89 authored by Simon Charette's avatar Simon Charette Committed by Tim Graham
Browse files

[1.5.x] Prevented data leakage in contrib.admin via query string manipulation.

This is a security fix. Disclosure following shortly.
parent dd68f319
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
from django.core.exceptions import SuspiciousOperation


class DisallowedModelAdminToField(SuspiciousOperation):
    """Invalid to_field was passed to admin view via URL query string"""
    pass
+18 −0
Original line number Diff line number Diff line
@@ -275,6 +275,24 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
        clean_lookup = LOOKUP_SEP.join(parts)
        return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy

    def to_field_allowed(self, request, to_field):
        opts = self.model._meta

        try:
            field = opts.get_field(to_field)
        except FieldDoesNotExist:
            return False

        # Make sure at least one of the models registered for this site
        # references this field.
        registered_models = self.admin_site._registry
        for related_object in opts.get_all_related_objects():
            if (related_object.model in registered_models and
                    field == related_object.field.rel.get_related_field()):
                return True

        return False

    def has_add_permission(self, request):
        """
        Returns True if the given request has permission to add an object.
+5 −1
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ from django.utils.translation import ugettext, ugettext_lazy
from django.utils.http import urlencode

from django.contrib.admin import FieldListFilter
from django.contrib.admin.exceptions import DisallowedModelAdminToField
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.util import (quote, get_fields_from_path,
    lookup_needs_distinct, prepare_lookup_value)
@@ -58,7 +59,10 @@ class ChangeList(object):
            self.page_num = 0
        self.show_all = ALL_VAR in request.GET
        self.is_popup = IS_POPUP_VAR in request.GET
        self.to_field = request.GET.get(TO_FIELD_VAR)
        to_field = request.GET.get(TO_FIELD_VAR)
        if to_field and not model_admin.to_field_allowed(request, to_field):
            raise DisallowedModelAdminToField("The field %s cannot be referenced." % to_field)
        self.to_field = to_field
        self.params = dict(request.GET.items())
        if PAGE_VAR in self.params:
            del self.params[PAGE_VAR]
+15 −0
Original line number Diff line number Diff line
@@ -47,3 +47,18 @@ and the ``RemoteUserBackend``, a change to the ``REMOTE_USER`` header between
requests without an intervening logout could result in the prior user's session
being co-opted by the subsequent user. The middleware now logs the user out on
a failed login attempt.

Data leakage via query string manipulation in ``contrib.admin``
===============================================================

In older versions of Django it was possible to reveal any field's data by
modifying the "popup" and "to_field" parameters of the query string on an admin
change form page. For example, requesting a URL like
``/admin/auth/user/?pop=1&t=password`` and viewing the page's HTML allowed
viewing the password hash of each user. While the admin requires users to have
permissions to view the change form pages in the first place, this could leak
data if you rely on users having access to view only certain fields on a model.

To address the issue, an exception will now be raised if a ``to_field`` value
that isn't a related field to a model that has been registered with the admin
is specified.
+15 −0
Original line number Diff line number Diff line
@@ -47,3 +47,18 @@ and the ``RemoteUserBackend``, a change to the ``REMOTE_USER`` header between
requests without an intervening logout could result in the prior user's session
being co-opted by the subsequent user. The middleware now logs the user out on
a failed login attempt.

Data leakage via query string manipulation in ``contrib.admin``
===============================================================

In older versions of Django it was possible to reveal any field's data by
modifying the "popup" and "to_field" parameters of the query string on an admin
change form page. For example, requesting a URL like
``/admin/auth/user/?pop=1&t=password`` and viewing the page's HTML allowed
viewing the password hash of each user. While the admin requires users to have
permissions to view the change form pages in the first place, this could leak
data if you rely on users having access to view only certain fields on a model.

To address the issue, an exception will now be raised if a ``to_field`` value
that isn't a related field to a model that has been registered with the admin
is specified.
Loading