2009-04-20 3 views
5

У меня есть приложение Django, которое я разрабатываю, чтобы сделать системный вызов внешней программы на сервере. При создании команды для системного вызова приложение принимает значения из формы и использует их в качестве параметров для вызова. Я полагаю, это означает, что можно по существу использовать фиктивные параметры и писать произвольные команды для выполнения оболочки (например, просто поместить точку с запятой, а затем rm -rf *).Как предотвратить выполнение произвольных команд из системных вызовов приложения Django?

Это плохо. Хотя большинство пользователей не являются злонамеренными, это потенциальная проблема безопасности. Как обрабатывать эти потенциальные точки эксплойта?

EDIT (для пояснения): пользователи будут видеть форму, разделенную различными полями для каждого из параметров и параметров. Однако некоторые поля будут доступны в виде открытых текстовых полей. Все эти поля объединяются и передаются в subprocess.check_call(). Технически, однако, это не отделяется слишком далеко от простого предоставления пользователям командной строки. Это должно быть довольно распространенным явлением, так что делают другие разработчики, чтобы дезинформировать входные данные, чтобы они не получили Bobby Tables.

ответ

10

Основываясь на моем понимании вопроса, я предполагаю, что вы не позволяете пользователям указывать команды для запуска в оболочке, а просто аргументы для этих команд. В этом случае вы можете избежать shell injection атак с помощью subprocess модуля и не с помощью оболочки (т.е. указать использовать параметр по умолчанию shell=False в subprocess.Popen конструктора.

О, и никогда использовать os.system() для любых строк, содержащих любой вход, поступающий от пользователя.

+0

Чтение через http://blog.littleimpact.de/index.php/2008/08/11/avoiding-shell-injection-in-ruby-python-and-php/ Кажется, я буду в порядке, поэтому long, как shell = False, по умолчанию. (То есть будет выполняться одна и только одна команда.) Это также то, что вы говорите? – gotgenes

+0

Да, вот что я говорю. –

3

Ответ: не разрешайте пользователям вводить команды оболочки! Нет никаких оправданий для разрешения произвольных команд оболочки.

Кроме того, если вы действительно должны разрешать пользователям предоставлять аргументы внешним командам, не используйте оболочку. В C вы можете использовать execvp() для предоставления аргументов непосредственно команде, но с помощью django я не уверен, как вы это сделаете (но я уверен, что есть способ). Разумеется, вы все равно должны сделать некоторые аргументы в области санитарии, особенно если команда может нанести какой-либо вред.

0

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

6

Не доверяйте пользователям. Любые данные, поступающие из веб-браузера, должны быть испорчены. И абсолютно не пытайтесь проверять данные через JS или ограничивать, что можно ввести в поля FORM Вам необходимо выполнить тесты на сервере, прежде чем передавать его на внешний интерфейс катион.

Обновление после вашего редактирования: Независимо от того, как вы представляете форму пользователям на своем интерфейсе, бэкэнд должен обрабатывать его, как если бы он исходил из набора текстовых полей с большим мигающим текстом вокруг них, говорящего «вставьте ты хочешь здесь!

+0

Хорошая точка. Я не предполагаю, что клиент будет отвечать и проверять; Перед выполнением команды я сделаю проверку на стороне сервера. Это стоит того, чтобы вы заявили, что на благо других. – gotgenes

4

Для этого необходимо выполнить следующие действия. Если вы не знаете, что такое «варианты» и «аргументы», прочитайте optparse background.

Каждая «команда» или «запрос» на самом деле является экземпляром модели. Определите модель вашего запроса со всеми параметрами, которые могут быть предоставлены пользователем.

  1. Для простых опций вы должны указать поле с определенным списком CHOICES. Для опций «включено» или «выключено» (-x в командной строке) вы должны предоставить список CHOICE с двумя понятными для человека значениями («Do X» и «Do not do X».)

  2. Для параметров со значением необходимо предоставить поле, которое принимает значение параметра. Вы должны написать форму с подтверждением для этого поля. Мы вернемся к проверке значения параметра немного.

  3. Для аргументов у вас есть вторая модель (с FK для первой). Это может быть просто, как одно поле FilePath, или может быть более сложным. Опять же, вам, возможно, придется предоставить форму для проверки экземпляров этой Модели.

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

Ваши варианты попадут в те же категории, что и типы опций в optparse - string, int, long, choice, float и complex. Обратите внимание, что int, long, float и complex имеют правила проверки, уже определенные в моделях и формах Django. Выбор - это особый тип строки, уже поддерживаемый моделями и формами Django.

Осталось слово «струны». Определите допустимые строки. Напишите регулярное выражение для этих строк. Подтвердите использование регулярного выражения. В большинстве случаев вы никогда не сможете принять котировки (", ' или `) в любой форме.

Заключительный этап. У вашей модели есть метод, который испускает команду как последовательность строк, все готовые для subprocess.Popen.


Редактировать

Это является основой нашего приложения. Это так часто, у нас есть одна модель с многочисленными формами, каждая из которых запускает специальную командную команду. Модель довольно общая. Формы - довольно специфические способы создания объекта Model. Именно так Django предназначен для работы, и он помогает соответствовать продуманным шаблонам дизайна Django.

Любое поле, доступное как открытое текстовое поле, является ошибкой. В каждом поле, которое открыто, должно быть регулярное выражение, чтобы указать, что разрешено. Если вы не можете формализовать регулярное выражение, вам нужно переосмыслить, что вы делаете.

Поле, которое не может быть ограничено регулярным выражением, не может быть параметром командной строки. Период. Прежде чем использовать его, он должен быть сохранен в столбце «Файл в базу данных».


Редактировать

Как это.

class MySubprocessCommandClass(models.Model): 
    myOption_1 = models.CharField(choice = OPTION_1_CHOICES, max_length=2) 
    myOption_2 = models.CharField(max_length=20) 
    etc. 
    def theCommand(self): 
     return [ "theCommand", "-p", self.myOption_1, "-r", self.myOption_2, etc. ] 

Ваша форма ModelForm для этой модели.

У вас нет необходимости в save() экземплярах модели. Мы сохраняем их, чтобы мы могли создать журнал точно, что было запущено.

+0

Спасибо за ваш ответ. Ответ Рика Коупленда указывает, что в модуле подпроцесса есть безопасность, в то время как shell = False, выполняется одна и только одна команда; все остальные части, следующие за исходной командой, рассматриваются как аргументы команды. Поскольку я управляю одной командой в начале, мне нужно действительно создавать регулярные выражения для аргументов? – gotgenes

+0

Кроме того, мне любопытно, почему нужна модель? Мне сложно скомпоновать все вместе, как вы заявили об этом. Наша форма уже представлена ​​как подкласс форм. Форма; мы используем это для проверки на данный момент. Как это связано с моделью. Является ли команда ссылкой на фактический (базовый) класс Command, из django.core.management.base? – gotgenes

+0

Ничего общего с иерархией Management.Command. Нет, эта команда полностью разделена. –

Смежные вопросы