Насколько безопасна оценка выражений с помощью eval?

Я создаю веб-сайт, на котором мне нужно, чтобы пользователь мог оценить какое-либо выражение на основе значения в таблицах БД, вместо использования таких инструментов, как pyparsing и т. Д., Я думаю об использовании самого python и придумал решение чего достаточно для моей цели. Я в основном использую eval для оценки выражения и передачи глобальных dict с пустым __builtins__, чтобы ничего нельзя было получить, и локальный dict для значений из БД, если пользователю понадобятся некоторые функции, я могу передать их, например,

import datetime
def today():
    return datetime.datetime.now()

expression = """ first_name.lower() == "anurag" and today().year == 2010 """

print eval(expression, {'__builtins__':{}}, {'first_name':'Anurag', 'today':today})

Итак, мой вопрос, насколько это безопасно, у меня есть три критерия.

  1. Может ли пользователь получить доступ к текущему состоянию моей программы или таблицы и т. Д. Someshow?
  2. Может ли пользователь иметь доступ к вызовам уровня ОС?
  3. Может ли пользователь остановить мою систему зацикливанием или использованием большого количества памяти, например. выполнив range (10 * 8), в некоторых случаях он может, например, 100 ** 1000 и т. д., поэтому 3 не является большой проблемой. Я могу проверить такую ​​операцию с помощью tokenize, и в любом случае я буду использовать GAE, поэтому это не вызывает особого беспокойства.

Изменить: ИМО, это не дубликат Q: 661084, потому что где он заканчивается, этот начинается, я хочу знать, может ли пользователь делать что-то плохое, даже если __builtins__ заблокирован?


person Anurag Uniyal    schedule 03.01.2010    source источник
comment
Проверьте: stackoverflow.com/questions / 661084 /   -  person fserb    schedule 03.01.2010


Ответы (3)


Совершенно небезопасно использовать eval, даже если встроенные модули очищены и заблокированы - злоумышленник может начать с литерала, получить его __class__ и т.д. слишком силен, чтобы противостоять опытному и решительному нападающему.

ast.literal_eval безопасно , если вы можете жить с его ограничениями ...

person Alex Martelli    schedule 03.01.2010
comment
хорошо, я вам верю :) но было бы весело, в любом случае я попробую PyParsing. - person Anurag Uniyal; 03.01.2010
comment
Подсказки, которую вы можете получить до любого типа или класса (перейдя на object, например, через __class__ и __mro__ или __bases__, затем вниз через __subclasses__, ...), должно быть достаточно в качестве контрпримера: пусть злонамеренные хакеры кто хочет разыграть деструктивные шалости хотя бы минутку поработать, чтобы построить свои решения ...! -) - person Alex Martelli; 03.01.2010

Конечно, можно использовать всю доступную память или создать бесконечный цикл даже без встроенных функций. Есть много способов сделать это, например 'a' * 999999 * 999999 или создать бесконечный цикл:

>>> print eval('[[x.append(a) for a in x] for x in [[0]]]',
...             {'__builtins__':{}}, {'first_name':'Anurag', 'today':today})

Что касается 1) и 2), я не уверен, но это выглядит рискованно. Вот одна вещь, которую я пробовал, и я думал, что она сработает, но кажется, что кто-то уже учел эту линию атаки и заблокировал ее:

>>> import datetime
>>> def today():
>>>     return datetime.datetime.now()
>>>
>>> print eval('today.func_globals', {'__builtins__':{}}, {'first_name':'Anurag', 'today':today})
RuntimeError: restricted attribute

Я почти ожидал получить вместо этого вот это:

{'__builtins__': <module '__builtin__' (built-in)>, ...

Так что я думаю, что это плохая идея. Вам понадобится всего одна крошечная дыра, и вы дадите доступ ко всей системе. Рассматривали ли вы другие методы, которые не используют eval? Что с ними не так?

person Mark Byers    schedule 03.01.2010
comment
да установка переменной builtins, включается режим ограниченного выполнения :) - person Anurag Uniyal; 03.01.2010
comment
+1 для «ограниченного атрибута», я не знал об этом, похоже, это из-за старого модуля reexec, я хотел использовать eval, потому что, если я могу, почему бы и нет? - person Anurag Uniyal; 03.01.2010

Можно создать и вызвать любой класс, определенный в программе, включая классы, которые могут выйти из интерпретатора Python. Кроме того, вы можете создавать и выполнять произвольные строки байт-кода, которые могут нарушить работу интерпретатора. Подробнее см. Eval действительно опасно.

person Ned Batchelder    schedule 09.06.2012