Почему должен должностное лицо () и оценка () избежаться?

Я видел это многократно в нескольких местах, но никогда не находил удовлетворяющее объяснение относительно того, почему это должно иметь место.

Так, надо надеяться, каждый будет представлен здесь. Почему должен, мы (по крайней мере, обычно) не используем exec() и eval()?

Править: Я вижу, что люди предполагают, что этот вопрос принадлежит веб-серверам – он не делает. Я вижу почему несанированная строка, передаваемая exec могло быть плохим. Это находится плохо в невеб-приложениях?

26
задан Isaac 19 December 2009 в 17:05
поделиться

11 ответов

Часто есть более четкие и прямые способы добиться того же эффекта. Если вы создадите сложную строку и передадите ее в exec, за кодом будет сложно следить и его сложно тестировать.

Пример: я написал код, который считывает строковые ключи и значения и устанавливает соответствующие поля в объекте. Это выглядело так:

for key, val in values:
    fieldName = valueToFieldName[key]
    fieldType = fieldNameToType[fieldName]
    if fieldType is int:
        s = 'object.%s = int(%s)' % (fieldName, fieldType) 
    #Many clauses like this...

exec(s)

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

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

19
ответ дан 28 November 2019 в 06:15
поделиться

eval () и exec () могут способствовать ленивому программированию. Что еще более важно, это указывает на то, что выполняемый код, возможно, не был написан во время разработки, поэтому не тестировался. Другими словами, как вы тестируете динамически сгенерированный код? Особенно в браузерах.

11
ответ дан 28 November 2019 в 06:15
поделиться

Когда вам нужны exec и eval, да, они вам действительно нужны.

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

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

Это ' Приманка струнных. Разбрасывание сегментов строки вокруг выглядит легким и обманывает наивных программистов, заставляя думать, что они понимают, что делают. Но опыт показывает, что результаты почти всегда неверны в некоторых угловых (или не очень) случаях, часто с потенциальными последствиями для безопасности. Вот почему мы говорим, что eval - это зло. Вот почему мы говорим, что регулярное выражение для HTML - зло. Вот почему мы продвигаем параметризацию SQL. Да, вы можете исправить все эти вещи с помощью ручной обработки строк ... но если вы еще не понимаете, почему мы говорим эти вещи, скорее всего, вы не будете .

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

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

12
ответ дан 28 November 2019 в 06:15
поделиться

Безопасность кроме того, eval и exec часто помечаются как нежелательные из-за сложности, которую они создают. Когда вы видите вызов eval , вы часто не знаете, что на самом деле происходит за ним, потому что он действует с данными, которые обычно находятся в переменной. Это затрудняет чтение кода.

Вызов полной мощности интерпретатора - тяжелое оружие, которое следует использовать только для очень сложных случаев. Однако в большинстве случаев этого лучше избегать и следует использовать более простые инструменты.

Тем не менее, как и все обобщения, остерегайтесь этого. В некоторых случаях могут оказаться полезными exec и eval. Но у вас должна быть очень веская причина их использовать. См. этот пост для одного допустимого использования.

10
ответ дан 28 November 2019 в 06:15
поделиться

В отличие от большинства здесь говорится, что exec на самом деле является частью рецепта для создания супер-полных декораторов в Python, поскольку вы можете точно дублировать все, что касается украшенной функции, создавая ту же подпись для целей документации и т. Это ключ к функциональности широко используемого модуля декоратора ( http://pypi.python.org/pypi/decorator/ ). Другие случаи, когда exec / eval важны, - это создание любого типа приложения «интерпретируемого Python», такого как язык шаблонов, анализируемый Python (например, Mako или Jinja).

Так что это не похоже на наличие этих функций. немедленный признак "

8
ответ дан 28 November 2019 в 06:15
поделиться

В прошлом я использовал eval () (и до сих пор время от времени использую) для обработки данных во время быстрых и грязных операций. Это часть набора инструментов, которую можно использовать для выполнения работы, но НИКОГДА не следует использовать для чего-либо, что вы планируете использовать в производственной среде , например, любых инструментов командной строки или сценариев, по всем причинам упомянутые в других ответах.

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

Прекрасным примером этого может служить использование Django при создании QuerySet . Параметры, передаваемые в запрос, принимают аргументы ключевого слова, которые выглядят примерно так:

results = Foo.objects.filter(whatever__contains='pizza')

Если вы программно назначаете аргументы, вы можете подумать сделать что-то вроде этого:

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))

Но всегда есть лучший способ, который не используйте eval () , который передает словарь по ссылке:

results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} ) 

Делая это таким образом, это не только быстрее с точки зрения производительности, но и безопаснее и более Pythonic.

Мораль истории?

Использование eval () нормально для небольших задач, тестов и действительно временных вещей, но плохо для постоянное использование, потому что почти всегда есть лучший способ сделать это!

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))

Но всегда есть лучший способ, который не использует eval () , который передает словарь по ссылке:

results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} ) 

Делая это таким образом, это не только быстрее с точки зрения производительности, но также безопаснее и питоннее.

Мораль истории?

Использование eval () нормально для небольших задач, тестов и действительно временных вещей, но плохо для постоянное использование, потому что почти всегда есть лучший способ сделать это!

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))

Но всегда есть лучший способ, который не использует eval () , который передает словарь по ссылке:

results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} ) 

Делая это таким образом, это не только быстрее с точки зрения производительности, но также безопаснее и питоннее.

Мораль истории?

Использование eval () нормально для небольших задач, тестов и действительно временных вещей, но плохо для постоянное использование, потому что почти всегда есть лучший способ сделать это!

6
ответ дан 28 November 2019 в 06:15
поделиться

Причина №1: Один недостаток безопасности (например, ошибки программирования ... и мы не можем утверждать, что их можно избежать), и вы только что предоставили пользователю доступ к оболочке сервера.

2
ответ дан 28 November 2019 в 06:15
поделиться

Попробуйте это в интерактивном интерпретаторе и посмотрите, что произойдет:

>>> import sys
>>> eval('{"name" : %s}' % ("sys.exit(1)"))

Конечно, это угловой случай, но предотвратить подобные вещи может быть сложно.

2
ответ дан 28 November 2019 в 06:15
поделиться

По той же причине, по которой вы не должны входить в систему как root: слишком легко выстрелить себе в ногу.

3
ответ дан 28 November 2019 в 06:15
поделиться
s = "import shutil; shutil.rmtree('/nonexisting')"
eval(s)

Теперь предположим, что кто-то может управлять s, например, из веб-приложения.

Не пытайтесь делать это на своем компьютере

3
ответ дан 28 November 2019 в 06:15
поделиться

Разрешение на использование этих функций в контексте, когда они могут запускать пользовательский ввод, является проблемой безопасности, а дезинфицирующие средства, которые действительно работают, трудно писать.

.
5
ответ дан 28 November 2019 в 06:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: