Как предотвратить выполнение произвольных команд из приложения Django, выполняющего системные вызовы? - PullRequest
5 голосов
/ 20 апреля 2009

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

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

РЕДАКТИРОВАТЬ (для пояснения): пользователи увидят форму, разделенную различными полями для каждого из параметров и опций. Однако некоторые поля будут доступны в виде открытых текстовых полей. Все эти поля объединяются и подаются на subprocess.check_call(). Технически, однако, это не отделено слишком далеко от простой передачи пользователям командной строки. Это должно быть довольно распространенным явлением, поэтому что другие разработчики делают для очистки ввода, чтобы они не получили таблиц Бобби .

Ответы [ 5 ]

10 голосов
/ 20 апреля 2009

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

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

6 голосов
/ 20 апреля 2009

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

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

4 голосов
/ 20 апреля 2009

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

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

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

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

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

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

Ваши опции попадают в те же категории, что и типы опций в optparse - string, int, long, choice, float и complex. Обратите внимание, что int, long, float и complex имеют правила проверки, уже определенные в моделях и формах 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() экземпляры модели. Мы сохраняем их, чтобы мы могли создать журнал того, что именно было запущено.

3 голосов
/ 20 апреля 2009

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

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

0 голосов
/ 20 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...