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

Если я оцениваю строку 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) без пользовательских словарей небезопасно в большинстве случаев.

6 ответов

Решение

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

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

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

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

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

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

Вы можете добраться до os используя встроенные функции: __import__('os'),

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

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

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

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

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

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

Цитируется из этой статьи:

В конце концов, можно безопасно оценить ненадежные выражения Python для некоторого определения "safe", которое оказывается не очень полезным в реальной жизни. Это хорошо, если вы просто играете вокруг, и это хорошо, если вы только когда-либо передаете это доверенным данным. Но все остальное просто напрашивается на неприятности.

Другие вопросы по тегам