Использование python eval() против ast.literal_eval()
У меня возникла ситуация с некоторым кодом, где eval() в качестве возможного решения было предложено. Мне никогда раньше не приходилось использовать eval(), но я наткнулся на множество информации о потенциальной опасности, которую это может вызвать. Тем не менее, я очень осторожно отношусь к его использованию.
Моя ситуация такова, что у меня есть входные данные, предоставляемые пользователем:
datamap = input('Provide some data here: ')
Где datamap должен быть словарь. Я поискал вокруг и обнаружил, что eval() может это решить. Я подумал, что, возможно, смогу проверить тип входных данных, прежде чем пытаться использовать данные, и это было бы разумной мерой предосторожности.
datamap = eval(input('Provide some data here: ') ifnotisinstance(datamap, dict): return
Я прочитал документы, и мне все еще неясно, будет ли это безопасно или нет. Eval оценивает данные сразу после их ввода или после того, как datamap вызывается переменная?
Является ли ast модуль .literal_eval() единственным безопасным вариантом?
Переведено автоматически
Ответ 1
datamap = eval(input('Provide some data here: ')) означает, что вы на самом деле оцениваете код, прежде чем сочтете его небезопасным. Он оценивает код сразу после вызова функции. Смотрите также об опасностях eval.
ast.literal_eval вызывает исключение, если входные данные не являются допустимым типом данных Python, поэтому код не будет выполнен, если это не так.
Используйте ast.literal_eval всякий раз, когда вам нужно eval. Обычно вам не следует оценивать буквальные операторы Python.
Ответ 2
ast.literal_eval() допустимым считается только небольшое подмножество синтаксиса Python:
Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строк, байтов, чисел, кортежей, списков, dicts, наборов, логических значений и None.
Передача __import__('os').system('rm -rf /a-path-you-really-care-about') в ast.literal_eval() вызовет ошибку, но eval() с радостью удалит ваши файлы.
Поскольку похоже, что вы разрешаете пользователю вводить только простой словарь, используйте ast.literal_eval(). Он безопасно выполняет то, что вы хотите, и ничего больше.
Ответ 3
eval: Это очень мощный метод, но также очень опасный, если вы принимаете строки для вычисления из ненадежных входных данных. Предположим, что вычисляемая строка - "os.system ('rm -rf /')" ? Это действительно приведет к удалению всех файлов на вашем компьютере.
ast.literal_eval: безопасно вычислять узел выражения или строку, содержащую литерал Python или отображение контейнера. Предоставленная строка или узел может состоять только из следующих литеральных структур Python: строк, байтов, чисел, кортежей, списков, dicts, наборов, логических значений, None, байтов и наборов.
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 object и function object из созданных экземпляров подклассов. Это альтернативный способ из CPython получить доступ к подклассам object и подключить систему.
В python 3.7 ast.literal_eval() теперь более строгий. Сложение и вычитание произвольных чисел больше не разрешено. Ссылка
Ответ 4
Python нетерпелив в своей оценке, поэтому eval(input(...)) (Python 3) оценит ввод пользователя, как только он попадет в eval, независимо от того, что вы делаете с данными впоследствии. Следовательно, это небезопасно, особенно при eval пользовательском вводе.
Использование ast.literal_eval.
В качестве примера, ввод этого параметра в командной строке может быть очень плохим для вас: