Является ли использование os.system ('curl & hellip;') в Python по-настоящему небезопасным по сравнению с родными библиотеками?

Хотя есть много хороших объяснений выше, я пропускаю практический способ разделения шаблонов на заголовок и тело. Моя главная задача - избегать перекомпиляции всех пользователей шаблонов, когда я меняю свое определение. Все экземпляры шаблонов в корпусе шаблона не являются жизнеспособным решением для меня, поскольку автор шаблона может не знать всех, если его использование и пользователь шаблона могут не иметь права его модифицировать. Я принял следующий подход, который также работает и для более старых компиляторов (gcc 4.3.4, aCC A.03.13).

Для каждого использования шаблона в его собственном файле заголовка (сгенерированном из модели UML) имеется typedef, , Его тело содержит экземпляр (который заканчивается в библиотеке, которая связана в конце). Каждый пользователь шаблона включает этот файл заголовка и использует typedef.

Схематический пример:

MyTemplate.h:

#ifndef MyTemplate_h
#define MyTemplate_h 1

template <class T>
class MyTemplate
{
public:
  MyTemplate(const T& rt);
  void dump();
  T t;
};

#endif

MyTemplate.cpp:

#include "MyTemplate.h"
#include <iostream>

template <class T>
MyTemplate<T>::MyTemplate(const T& rt)
: t(rt)
{
}

template <class T>
void MyTemplate<T>::dump()
{
  cerr << t << endl;
}

MyInstantiatedTemplate.h:

#ifndef MyInstantiatedTemplate_h
#define MyInstantiatedTemplate_h 1
#include "MyTemplate.h"

typedef MyTemplate< int > MyInstantiatedTemplate;

#endif

MyInstantiatedTemplate.cpp:

#include "MyTemplate.cpp"

template class MyTemplate< int >;

main.cpp:

#include "MyInstantiatedTemplate.h"

int main()
{
  MyInstantiatedTemplate m(100);
  m.dump();
  return 0;
}

Таким образом, нужно будет перекомпилировать только экземпляры шаблонов, не всех пользователей шаблонов (и зависимостей).

-1
задан Vladimir_314159 13 July 2018 в 17:37
поделиться

2 ответа

Возражение полностью законно.

Предположим, что ваша команда выглядит так:

def post_result(result_string):
  os.system('curl http://example.com/report-result/%s' % (result_string,))

Теперь, что произойдет, если вам сообщают о результатах, которые содержат ; rm -rf ~? Оболочка, вызванная os.system(), запускает curl http://example.com/report-result/, а затем выполняет вторую команду rm -rf ~.

Несколько наивных попыток исправления не работают.

например:

# Adding double quotes should work, right?
# WRONG: ''; rm -rf ~'' doesn't work here, but $(rm -rf ~) still does.
os.system('curl http://example.com/report-result/"%s"' % (result_string,))

# ...so, how about single quotes?
# STILL WRONG: $(rm -rf ~) doesn't work on its own, but result_string="'$(rm -rf ~)'" does.
os.system("curl http://example.com/report-result/'%s'" % (result_string,))

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

Во время запуска оболочка выполняет ряд операций на основе содержимого файловой системы и переменных среды. Если ненадежный пользователь может манипулировать вашей программой в настройке переменных окружения по своему выбору до вызова os.system(), они могут заставить файл с именем в ENV выполнить свои команды; может теневые команды с экспортированными функциями или может вызвать другие озорства. См. ShellShock для хорошо опубликованного исторического примера.

И прежде чем рассматривать другие вещи, которые могут случиться с вашими данными. Если вы передаете имя файла в оболочку, но неизвестно вам, оно содержит символы пробелов и glob, это имя файла может быть разделено на / заменено другими именами.


Официальная документация Python предупреждает против shell.

Цитирование предупреждения из документации модуля Python subprocess , что также актуально здесь:

Предупреждение: выполнение команд оболочки которые включают неанитированный ввод из ненадежного источника, делают программу уязвимой для инъекции оболочки, серьезную проблему безопасности, которая может привести к произвольному выполнению команды. По этой причине использование shell=True сильно не рекомендуется в случаях, когда командная строка построена из внешнего ввода:

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

shell=False отключает все функции на основе оболочки, но не страдает от этого уязвимость; см. примечание в документации конструктора Popen для полезных подсказок при работе shell=False.

При использовании shell=True, pipes.quote() можно использовать для правильного удаления пробелов и метасимволов оболочки в строках, которые будут использоваться для создания команд оболочки.

os.system() имеет все те же ошибки, что и subprocess.Popen(..., shell=True) - даже больше сбоев, поскольку subprocess.Popen() обеспечивает способ передачи данных вне диапазона из кода, и поэтому можно безопасно использовать .


Исходные библиотеки Python не вызывают оболочки для работы, которые Python может работать.

Python имеет библиотеку socket в своем стандартном библиотечном интерфейсе, который непосредственно вызывает вызовы операционной системы и libc для создания сетевых подключений и взаимодействия с ними. В этих системных вызовах нет оболочки; аргументами являются C-структуры, строки C и т. д .; поэтому они не подвержены уязвимостям инъекции оболочки так же, как os.system().

Некоторые библиотеки Python, такие как libcurl, могут быть немного менее родными, поскольку они используют свои собственные библиотеки C, а чем вызов только операционной системе через функции, входящие в состав самой Python; даже тогда эти системные системы на уровне OS находятся на гораздо более низком уровне, чем любая оболочка.

1
ответ дан Charles Duffy 17 August 2018 в 12:26
поделиться
  • 1
    Это тот случай, когда строки передаются, если вы были жестким кодом, это было бы безопаснее, но вызов оболочки - это не то, что вы бы назвали оптимизацией, так что да, построенный полностью. – Dusan Gligoric 13 July 2018 в 16:15

Этот ответ полностью верен. Но я также хотел бы указать на другие случаи, когда вы могли бы подумать, что безопасность не имеет значения. Например. команда, которую вы запускаете, жестко запрограммирована или у вас есть 100% контроль или доверие к тому, что ему предоставляется. Даже в этом случае os.system() неверно . Фактически:

  • Вы должны полагаться на внешние инструменты, которые могут отсутствовать или, что еще хуже, у вас может быть команда a с этим именем, но она не " делайте то, что вы ожидаете от этого. Может быть, потому, что у него другая версия или, возможно, потому, что это другая реализация этой команды (например, GNUtar! = BSDtar). Зависимые зависимости python будут намного проще и надежнее.
  • С ошибками справиться сложнее. У вас есть код возврата, который не всегда достаточно, чтобы понять, что происходит. И я надеюсь, что ваше решение этой проблемы заключается не в анализе вывода команды.
  • Переменные среды могут изменить способ работы программы неожиданно. Многие программы используют переменные среды в качестве альтернативы командной строке или параметрам конфигурации. Если ваш скрипт python полагается на определенное поведение из команды, неожиданная переменная в среде пользователя может ее сломать.
  • Если в какой-то момент в будущем вам нужно будет немного настроить поведение вашего скрипта вам нужно будет переписать его с нуля без os.system() или у вас могут быть проблемы с безопасностью.
0
ответ дан smeso 17 August 2018 в 12:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: