Безопасность Python eval () для ненадежных строк?

Если я оцениваю строку Python с помощью eval () и имею такой класс, как:

class Foo(object):
    a = 3
    def bar(self, x): return x + a

Каковы риски безопасности, если я не доверяю строке? Особенно:

  1. eval(string, {"f": Foo()}, {}) небезопасно? То есть можно ли получить доступ к os, sys или чему-то небезопасному из экземпляра Foo?
  2. eval(string, {}, {}) небезопасно? То есть могу ли я получить доступ к os или sys полностью с помощью встроенных команд, таких как len и list?
  3. Есть ли способ сделать так, чтобы встроенные функции вообще не присутствовали в контексте eval?

Есть некоторые небезопасные строки, такие как «[0] * 100000000», которые меня не волнуют, потому что в худшем случае они замедляют / останавливают программу. Меня в первую очередь беспокоит защита внешних по отношению к программе пользовательских данных.

Очевидно, eval(string) без пользовательских словарей в большинстве случаев небезопасно.


person Community    schedule 19.03.2009    source источник
comment
да, если есть import sys sys.dostuff в строке, в которой вы выполняете eval, и вы не доверяете строкам, материал может стать действительно уродливым.   -  person Vasil    schedule 19.03.2009
comment
eval имеет приятное свойство: он допускает только выражения. Поэтому такие вещи, как =, import и print, не разрешены.   -  person    schedule 19.03.2009
comment
Попробуйте eval('__import__("sys").stdout.write("Hello Joe")')   -  person John La Rooy    schedule 07.12.2010


Ответы (6)


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

person Ned Batchelder    schedule 09.06.2012

eval() позволит вредоносным данным поставить под угрозу всю вашу систему, убить вашу кошку, съесть вашу собаку и заняться любовью с вашей женой.

Недавно была ветка о том, как безопасно делать такие вещи в списке python-dev, и были сделаны следующие выводы:

  • Это действительно сложно сделать как следует.
  • Требуются патчи к интерпретатору Python, чтобы блокировать многие классы атак.
  • Не делайте этого, если вы действительно этого не хотите.

Начните здесь, чтобы прочитать о проблеме: http://tav.espians.com/a-challenge-to-break-python-security.html.

В какой ситуации вы хотите использовать eval ()? Вы хотите, чтобы пользователь мог выполнять произвольные выражения? Или вы хотите каким-то образом передать данные? Возможно, можно каким-то образом заблокировать ввод.

person Jerub    schedule 19.03.2009
comment
@S. Лотт - Не является ли одна из движущих идей безопасности предотвращения плохих вещей, а не надежда на то, что вы сможете идентифицировать злоумышленника и убедить его не делать этого снова? Зачем препятствовать передовой практике? - person Ben Blank; 19.03.2009
comment
Любая ситуация, когда человек в большом Интернете для написания ненадежного кода для запуска в ваших системах, требует, чтобы недоверенные лица не могли атаковать. Кто этот человек - если вы написали что-то небезопасное с помощью eval (), а я знал? Это было бы я, чтобы показать вам, что вы не должны были этого делать. - person Jerub; 20.03.2009

Вы можете перейти к os с помощью встроенных функций: __import__('os').

Для python 2.6+ может помочь модуль ast; в частности ast.literal_eval, хотя это зависит от того, что именно вы хотите оценить.

person John Fouhy    schedule 19.03.2009

Обратите внимание, что даже если вы передадите в eval () пустые словари, все равно возможно выполнить segfault (C) Python с помощью некоторых синтаксических трюков. Например, попробуйте это на своем интерпретаторе: eval("()"*8**5)

person Benjamin Peterson    schedule 19.03.2009
comment
Ого, почему это привело к сбою в работе? - person jacob; 01.03.2010
comment
Он переполняет стек компилятора. - person Benjamin Peterson; 08.04.2010

Вам, вероятно, лучше перевернуть вопрос:

  1. Какие выражения вы хотите оценивать?
  2. Можете ли вы сделать так, чтобы eval () d были только строками, соответствующими некоторому узко определенному синтаксису?
  3. Затем подумайте, это безопасно.

Например, если вы хотите, чтобы пользователь вводил алгебраическое выражение для оценки, рассмотрите возможность ограничения их именами переменных из одной буквы, числами и определенным набором операторов и функций. Не используйте eval () в строках, содержащих что-либо еще.

person MarkusQ    schedule 19.03.2009
comment
@ S.Lott - Если он пишет программы криптографии, то это либо Кэрол, либо Ева, а для обработки электронной почты это [email protected], но я не знаю, идентифицировали ли мы когда-либо, кто это в общем случае. - person MarkusQ; 19.03.2009
comment
Я бы пошел на шаг впереди и спросил бы почему вы вообще хотите это делать. - person Noufal Ibrahim; 03.01.2010
comment
Это хорошее видео под названием 28c3: The Science of Insecurity, в котором описываются интерфейсы между программами. www.youtube.com/watch?v=3kEfedtQVOY Он настоятельно рекомендует, чтобы входные сообщения были либо обычными, либо контекстными. - person eric.frederich; 20.01.2012

В книге Марка Пилигрима есть очень хорошая статья о небезопасности eval() Руководство по погружению в Python.

Цитата из этой статьи:

В конце концов, можно безопасно оценивать ненадежные выражения Python для некоторого определения «безопасного», которое оказывается не очень полезным в реальной жизни. Ничего страшного, если вы просто играете, и ничего страшного, если вы передадите только надежные данные. Но все остальное просто напрашивается на неприятности.

person Tim Pietzcker    schedule 03.01.2010
comment
Ссылка больше не действительна. - person GingerPlusPlus; 21.11.2014
comment
@GingerPlusPlus: Спасибо, похоже, Марк переместил свой домен. Я обновил ссылки. - person Tim Pietzcker; 22.11.2014