block users from making looping filters which can DoS Tower

This commit is contained in:
AlanCoding
2017-03-21 10:16:49 -04:00
parent bdc222351f
commit 925712e3ec
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)