Хотя есть много хороших объяснений выше, я пропускаю практический способ разделения шаблонов на заголовок и тело. Моя главная задача - избегать перекомпиляции всех пользователей шаблонов, когда я меняю свое определение. Все экземпляры шаблонов в корпусе шаблона не являются жизнеспособным решением для меня, поскольку автор шаблона может не знать всех, если его использование и пользователь шаблона могут не иметь права его модифицировать. Я принял следующий подход, который также работает и для более старых компиляторов (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;
}
Таким образом, нужно будет перекомпилировать только экземпляры шаблонов, не всех пользователей шаблонов (и зависимостей).
Предположим, что ваша команда выглядит так:
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 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 находятся на гораздо более низком уровне, чем любая оболочка.
Этот ответ полностью верен. Но я также хотел бы указать на другие случаи, когда вы могли бы подумать, что безопасность не имеет значения. Например. команда, которую вы запускаете, жестко запрограммирована или у вас есть 100% контроль или доверие к тому, что ему предоставляется. Даже в этом случае os.system()
неверно . Фактически:
os.system()
или у вас могут быть проблемы с безопасностью.