Использование python eval() против ast.literal_eval()?
У меня есть ситуация с некоторым кодом, где eval()
появился как возможное решение. Теперь у меня никогда не было
использовать eval()
раньше, но я нашел много информации о потенциале
опасность, которую это может вызвать. Тем не менее, я очень опасаюсь использовать его.
Моя ситуация в том, что у меня есть ввод, предоставляемый пользователем:
datamap = raw_input('Provide some data here: ')
Где datamap
должен быть словарь. Я обыскал и обнаружил, что eval()
может это решить.
Я думал, что я могу проверить тип ввода, прежде чем пытаться использовать данные, и что
будет жизнеспособной мерой предосторожности.
datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
return
Я прочитал документы, и я до сих пор неясно, будет ли это безопасно или нет. Оценивает ли eval данные сразу после его ввода или после вызова переменной datamap
?
Является ли ast
модулем .literal_eval()
единственным безопасным вариантом?
Ответы
Ответ 1
datamap = eval(raw_input('Provide some data here: '))
означает, что вы действительно оцениваете код, прежде чем считаете его небезопасным или нет. Он оценивает код, как только вызывается функция. См. Также опасности eval
.
ast.literal_eval
вызывает исключение, если вход не является допустимым типом данных Python, поэтому код не будет выполнен, если он не был.
Используйте ast.literal_eval
, когда вам нужно eval
. Обычно вы не должны оценивать литералы с помощью Python.
Ответ 2
ast.literal_eval()
учитывает только малую часть синтаксиса Python:
Строка или node может содержать только следующие литературные структуры Python: строки, числа, кортежи, списки, dicts, booleans и None.
Передача __import__('os').system('rm -rf /a-path-you-really-care-about')
в ast.literal_eval()
вызовет ошибку, но eval()
с удовольствием уничтожит ваш диск.
Поскольку похоже, что вы разрешаете пользователю вводить простой словарь, используйте ast.literal_eval()
. Он безопасно делает то, что вы хотите, и не более того.
Ответ 3
Python нетерпелив в своей оценке, поэтому eval(raw_input(...))
будет оценивать ввод пользователя, как только он попадает в eval
, независимо от того, что вы делаете с данными впоследствии. Поэтому это не безопасно, особенно если вы eval
вводите пользователя.
Используйте ast.literal_eval
.
В качестве примера, ввод этого в подсказку будет очень, очень плохо для вас:
__import__('os').system('rm -rf /a-path-you-really-care-about')
Ответ 4
eval: это очень мощно, но также очень опасно, если вы принимаете строки для оценки из ненадежного ввода. Предположим, что оцениваемой строкой является "os.system('rm -rf/')"? Это действительно начнет удалять все файлы на вашем компьютере.
ast.literal_eval: Безопасный анализ узла выражения или строки, содержащей литерал Python или отображение контейнера. Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строк, байтов, чисел, кортежей, списков, диктов, наборов, логических значений, None, байтов и наборов.
Синтаксис:
eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)
Пример:
# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]') # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string
# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error
eval("__import__('os').system('rm -rf /')")
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing '__builtins__':{} in global
# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
c for c in
().__class__.__bases__[0].__subclasses__()
if c.__name__ == n
][0]
):
fc("function")(
fc("code")(
0,0,0,0,"KABOOM",(),(),(),"","",0,""
),{}
)()
)()
"""
eval(s, {'__builtins__':{}})
В приведенном выше коде ().__class__.__bases__[0]
только объект. Теперь мы создали все подклассы, здесь наша основная цель enter code here
- найти из него один класс с именем n.
Нам нужно code
объект и function
объект из созданных экземпляров подклассов. Это альтернативный способ из CPython
получить доступ к подклассам объекта и подключить систему.
В python 3.7 ast.literal_eval() теперь стал более строгим. Сложение и вычитание произвольных чисел больше не допускаются. ссылка на сайт
Ответ 5
Если вам нужен только пользовательский словарь, возможно лучшее решение - json.loads
. Основное ограничение заключается в том, что json dicts требует строковых ключей. Также вы можете предоставить только литеральные данные, но это также относится к literal_eval
.
Ответ 6
Я застрял с ast.literal_eval()
. Я пробовал это в отладчике IntelliJ IDEA, и он возвращал None
при выводе отладчика.
Но позже, когда я назначил ее вывод переменной и напечатал ее в коде. Работало нормально. Пример совместного использования кода:
import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)
Его версия Python 3.6.