Django: SQL Injection-proof Manager.py

У меня есть файл manager.py, который использует параметр.extra() для выполнения необработанных запросов SQL. Например:

class MyManager(models.Manager):

    def order_null_last(self, field):
        return super(DecisionManager, self).get_query_set()\
            .extra(select={'has_field': "CASE WHEN " + field + " IS NULL THEN 1 ELSE 0 END"}).order_by('has_field', field)

Мне было предложено, что этот вид запроса может быть уязвим для атаки путем инъекции.

Переменная 'field' анализируется, чтобы убедиться, что она принадлежит группе допустимых значений, но эта проверка выполняется в представлении. Например:

class ModelList(ListView):
    model = MyModel

    def get(self, request, *args, **kwargs):
        self.set_sorting(request)

    def set_sorting(self, request):
        self.sort_field = request.GET.get('sort', '-id')
        if not self.sort_field in self.sort_options:
            self.sort_field = 'id'

Так что, если кто-то написал новое представление с помощью вышеприведенного менеджера, но забыл отфильтровать параметры, то эксплойт будет возможен.

Итак, есть ли способ проверить параметр по полям моделей в менеджере, не получая циклический импорт? То есть менеджеру необходимо импортировать модель, чтобы получить список разрешенных полей, но модели необходимо импортировать менеджер.

2 ответа

Использование select_params во избежание SQL-инъекций:

class MyManager(models.Manager):

def order_null_last(self, field):
    return super(DecisionManager, self).get_query_set()\
        .extra(select={'has_field': "CASE WHEN %s IS NULL THEN 1 ELSE 0 END"}, select_params=(field,)).order_by('has_field', field)

Менеджер моделей имеет доступ к моделям и, следовательно, к полям через self.model.

Так что я могу написать это:

Класс MyManager(models.Manager):

def order_null_last(self, field):
    if field in [modelfield.name for modelfield in self.model._meta.fields]:
        return super(DecisionManager, self).get_query_set()\
            .extra(select={'has_field': "CASE WHEN " + field + " IS NULL THEN 1 ELSE 0 END"}).order_by('has_field', field)
    else:
        return super(DecisionManager, self).get_query_set()
Другие вопросы по тегам