Merge pull request #5812 from AlanCoding/no_loops_for_hackers

Block loops in querystring filters
This commit is contained in:
Alan Rominger
2017-03-21 10:50:35 -04:00
committed by GitHub
2 changed files with 15 additions and 1 deletions

View File

@@ -92,6 +92,9 @@ class FieldLookupBackend(BaseFilterBackend):
# sure user cannot query using objects he could not view. # sure user cannot query using objects he could not view.
new_parts = [] new_parts = []
# Store of all the fields used to detect repeats
field_set = set([])
for name in parts[:-1]: for name in parts[:-1]:
# HACK: Make project and inventory source filtering by old field names work for backwards compatibility. # HACK: Make project and inventory source filtering by old field names work for backwards compatibility.
if model._meta.object_name in ('Project', 'InventorySource'): if model._meta.object_name in ('Project', 'InventorySource'):
@@ -124,6 +127,10 @@ class FieldLookupBackend(BaseFilterBackend):
raise PermissionDenied(_('Filtering on %s is not allowed.' % name)) raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
elif getattr(field, '__prevent_search__', False): elif getattr(field, '__prevent_search__', False):
raise PermissionDenied(_('Filtering on %s is not allowed.' % name)) raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
if field in field_set:
# Field traversed twice, could create infinite JOINs, DoSing Tower
raise ParseError(_('Loops not allowed in filters, detected on field {}.').format(field.name))
field_set.add(field)
model = getattr(field, 'related_model', None) or field.model model = getattr(field, 'related_model', None) or field.model
if parts: if parts:

View File

@@ -2,7 +2,7 @@
import pytest import pytest
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied, ParseError
from awx.api.filters import FieldLookupBackend from awx.api.filters import FieldLookupBackend
from awx.main.models import (AdHocCommand, AuthToken, CustomInventoryScript, from awx.main.models import (AdHocCommand, AuthToken, CustomInventoryScript,
Credential, Job, JobTemplate, SystemJob, Credential, Job, JobTemplate, SystemJob,
@@ -77,3 +77,10 @@ def test_filter_sensitive_fields_and_relations(model, query):
with pytest.raises(PermissionDenied) as excinfo: with pytest.raises(PermissionDenied) as excinfo:
field, new_lookup = field_lookup.get_field_from_lookup(model, query) field, new_lookup = field_lookup.get_field_from_lookup(model, query)
assert 'not allowed' in str(excinfo.value) assert 'not allowed' in str(excinfo.value)
def test_looping_filters_prohibited():
field_lookup = FieldLookupBackend()
with pytest.raises(ParseError) as loop_exc:
field_lookup.get_field_from_lookup(Job, 'job_events__job__job_events')
assert 'job_events' in str(loop_exc.value)