Почему использовать eval() опасно?
Я пишу код для калькулятора (т.е., вписал пример и получил ответ).
Я нашёл способ использовать eval(), но говорят, что он опасен.
Чем он опасен и чем можно заменить его?
Ответы (2 шт):
Документация python:
eval(expression, globals=None, locals=None)
Параметры:
expression (str | code object) – Python выражение (Проще Python код)
...
Аргумент expression анализируется и оценивается как Python выражение (Проще Python код) ...
То есть, eval
буквально позволяет выполнить все, что вы в него сунете. Представьте, как пользователь вашего калькулятора пишет в поле ввода os.shutdown()
. Ваш код:
expression = input()
eval(exspression)
Expression
выполнится, компьютер выключится, а вы останетесь без преданного пользователя.
Безусловно, звучит как анекдот. В своем калькуляторе вы можете использовать eval
без угрызений совести, так как ответственность за ввод - вы. Но в реальных проектах eval
следует использовать с осторожностью.
При желании eval
можно заменить простой функцией, к примеру:
def main():
expression = input()
first_number = ""
index = 0
while expression[index].isdigit():
first_number += expression[index]
index += 1
operator = expression[index]
second_number = expression[index+1:]
if operator == "+":
print(int(first_number) + int(second_number))
elif operator == "-":
print(int(first_number) - int(second_number))
elif operator == "*":
print(int(first_number) * int(second_number))
elif operator == "/":
print(int(first_number) / int(second_number))
В контексте калькулятора, накидал простую проверку на безопасность входного выражения:
import math
import re
def safe_eval(string):
allowed_chars = set('0123456789+-*/(). aceinopqstr')
danger_keys = {'not', 'is', 'in', 'or', 'and', 'assert', 'raise', 'import', 'exec', 'eval', 'Ellipsis', 'as', 'case', 'pass'}
if set(string) - allowed_chars:
raise ValueError("Выражение содержит недопустимые символы")
for keyword in danger_keys:
if re.search(r'\b' + re.escape(keyword) + r'\b', string):
raise ValueError("Выражение содержит недопустимые ключевые слова")
return eval(string, {'__builtins__': {'sin': math.sin, 'cos': math.cos, 'tan': math.tan, 'sqrt': math.sqrt, 'pi': math.pi, 'e': math.e}})
safe = "sqrt(tan(54) - cos((2.8 + 3) * sin(pi / 4) + 10.5e-3))"
try:
result = safe_eval(safe)
print(f"Результат: {result}")
except Exception as e:
print(f"Ошибка: {e}")
danger = "__import__('os').shutdown()"
try:
result = safe_eval(danger)
print(f"Результат: {type(result)}")
except Exception as e:
print(f"Ошибка: {e}")