Большинство современных языков (которые так или иначе интерпретируются) имеют какую-то функцию оценки . Такая функция выполняет произвольный код языка, большую часть времени передаваемый в качестве основного аргумента в виде строки (разные языки могут добавлять больше функций в функцию eval).
Я понимаю, что пользователям нельзя разрешать выполнять эту функцию ( редактировать, то есть принимать прямо или косвенно произвольный ввод от произвольного пользователя для передачи eval
), особенно с программным обеспечением на стороне сервера, поскольку они могут заставить процесс выполнять вредоносный код. Таким образом, учебники и сообщества говорят нам не использовать eval. Однако во многих случаях eval полезен и используется:
- Пользовательские правила доступа к программным элементам (IIRC OpenERP имеет объект,
ir.rule
который может использовать динамический код Python). - Пользовательские вычисления и / или критерии (OpenERP имеет такие поля, чтобы разрешить пользовательские вычисления кода).
- Парсеры отчетов OpenERP (да, я знаю, я волнуюсь из-за материала OpenERP ... но это основной пример, который у меня есть).
- Кодирование эффектов заклинаний в некоторых ролевых играх.
Таким образом, они имеют хорошее применение, если они используются правильно. Основным преимуществом является то, что эта функция позволяет администраторам писать собственный код без необходимости создавать больше файлов и включать их (хотя в большинстве сред, использующих функции eval, также есть способ указать файл, модуль, пакет, ... для чтения).
Тем не менее, Eval является злом в массовой культуре. Такие вещи, как проникновение в вашу систему, приходят на ум.
Однако существуют и другие функции, которые могут быть вредными, если пользователи каким-либо образом к ним обращаются: отсоединение, чтение, запись (семантика файла), распределение памяти и арифметика указателей, доступ к модели базы данных (даже если не учитывать случаи инъекции SQL).
Таким образом, в основном, в большинстве случаев, когда какой-либо код написан неправильно или не отслеживается должным образом (ресурсы, пользователи, окружение, ...), код является злым и может привести даже к экономическим последствиям.
Но есть что-то особенное с eval
функциями (независимо от языка).
Вопрос : Есть ли исторический факт, что этот страх становится частью популярной культуры вместо того, чтобы уделять такое же внимание другим, возможно, опасным чертам?
источник
eval
, а имеет внутреннюю функцию,safe_eval
которая подготавливает среду для предотвращения опасных действий кода. Однако были найдены ошибки, поскольку Python - довольно гибкий язык, и поэтому его трудно контролировать.Ответы:
eval
Функция сама по себе не является злом, и есть тонкий момент , который я не верю , что вы делаете:Разрешение программе выполнять произвольный пользовательский ввод плохо
Я написал код, который использовал
eval
тип функции, и это было безопасно: программа и параметры были жестко запрограммированы. Иногда нет языка или библиотечной функции, чтобы сделать то, что нужно программе, и выполнение команды оболочки - короткий путь. «Я должен закончить кодирование за несколько часов, но написание Java / .NET / PHP / любого кода займет два дня. Или я могу сделатьeval
это за пять минут».Как только вы разрешаете пользователям выполнять все, что они хотят, даже если они заблокированы привилегиями пользователя или за «безопасным» экраном, вы создаете векторы атак. Каждую неделю в некоторых случайных CMS, программах для ведения блогов и т. Д. Исправляется дыра в безопасности, где злоумышленник может использовать такую дыру. Вы полагаетесь на весь программный стек, чтобы защитить доступ к функции, которая может быть использована
rm -rf /
или к чему-то еще катастрофическому (примечание: эта команда вряд ли будет успешной, но потерпит неудачу после нанесения небольшого ущерба).Да, есть исторический прецедент. Из-за многочисленных ошибок, которые исправлялись в течение многих лет в различном программном обеспечении, позволяющем удаленным злоумышленникам выполнять произвольный код, идея в
eval
основном потеряла популярность. Современные языки и библиотеки имеют богатый набор функций, которые делаютeval
менее важными, и это не случайно. Это облегчает использование функций и снижает риск эксплойта.Много внимания было уделено многим потенциально небезопасным функциям в популярных языках. Вопрос о том, получает ли кто-то больше внимания, - это, прежде всего, вопрос мнения, но
eval
функции, безусловно, имеют доказуемую проблему безопасности, которую легко понять. Например, они позволяют выполнять команды операционной системы, в том числе встроенные оболочки и стандартные программы (например,rm
илиdel
). Во-вторых, в сочетании с другими эксплойтами, злоумышленник может загрузить свой собственный исполняемый файл или скрипт оболочки, а затем запустить его через ваше программное обеспечение, открывая дверь для почти всего, что может произойти (ничего из этого не получается).Это сложная проблема. Программное обеспечение является сложным, и программный стек (например, LAMP ) представляет собой множество программных продуктов, которые взаимодействуют друг с другом сложными способами. Будьте осторожны при использовании языковых функций, таких как эта, и никогда не позволяйте пользователям выполнять произвольные команды.
источник
eval
может повысить привилегии. что не проблема, если они уже повышены.rm -rf /
, нет необходимости делать это сложным образом через IDE. Проблема вeval
том, что она открывает эту способность для многих актеров, у которых не должно быть этой способности.Отчасти это просто, что нюанс сложен. Легко сказать, что никогда не использовать goto, открытые поля, интерполяцию строк для SQL-запросов или eval. Эти утверждения не следует понимать как говорящие о том, что никогда и ни при каких обстоятельствах нет причин использовать их. Но избегать их как общее правило - хорошая идея.
Eval сильно обескуражен, потому что он объединяет несколько общих проблем.
Во-первых, он подвержен инъекционным атакам. Здесь это похоже на SQL-инъекцию в том, что когда пользовательские данные вставляются в код, можно легко случайно вставить произвольный код.
Во-вторых, новички склонны использовать eval для обхода плохо структурированного кода. Начинающий кодер может написать код, который выглядит следующим образом:
Это работает, но это действительно неправильный способ решить эту проблему. Очевидно, что использование списка было бы лучше.
В-третьих, eval обычно неэффективен. Много усилий уходит на ускорение реализации наших языков программирования. Но eval трудно ускорить, и его использование, как правило, отрицательно сказывается на вашей производительности.
Итак, Эвал не является злом. Мы можем сказать, что eval - это зло, потому что это очень запоминающийся способ выразить это. Любой начинающий программист должен строго держаться подальше от eval, потому что, что бы они ни хотели сделать, eval - почти наверняка неправильное решение. Для некоторых расширенных вариантов использования eval имеет смысл, и вы должны его использовать, но, очевидно, будьте осторожны с подводными камнями.
источник
var x = 3; print(x)
будет собран , то есть не нужно быть любым время выполнения знания о том , что источник используется название «х». Для того,var x = 3; print(eval("x"))
чтобы работать, это отображение должно быть записано. Это реальная проблема: в Common Lisp(let ((x 3)) (print (eval 'x)))
выдается исключение несвязанной переменной, потому что лексическая переменная x не имеет никакой связи с именем после компиляции кода.То, к чему это сводится, - то, что "выполнение произвольного кода" - технический разговор для "способного сделать что-нибудь". Если кто-то может использовать выполнение произвольного кода в вашем коде, это буквально самая худшая из возможных уязвимостей безопасности, потому что это означает, что он может делать все, что возможно для вашей системы.
«Другие, возможно, вредные ошибки» вполне могут иметь ограничения, что означает, что они по определению способны причинить меньше вреда, чем использование произвольного исполнения кода.
источник
eval
.Есть практическая и теоретическая причина.
Практическая причина в том, что мы наблюдаем, что это часто вызывает проблемы. Редко, когда eval приводит к хорошему решению, и это часто приводит к плохому решению, где в итоге вы получили бы лучшее, если бы притворялись, что eval не существует, и подходите к проблеме по-другому. Таким образом, упрощенный совет состоит в том, чтобы игнорировать его, и если вы придете к случаю, когда вы хотите игнорировать упрощенный совет, давайте надеяться, что вы продумали его достаточно, чтобы понять, почему упрощенный совет не применим и что общего ловушки не повлияют на вас.
Более теоретическая причина в том, что если сложно написать хороший код, то еще сложнее написать код, который пишет хороший код. Используете ли вы eval, или генерируете операторы SQL, склеивая строки, или пишете JIT-компилятор, то, что вы пытаетесь сделать, зачастую сложнее, чем вы ожидаете. Потенциальная возможность внедрения вредоносного кода - одна большая часть проблемы, но, кроме того, как правило, сложнее узнать правильный код, если он вообще не существует до времени выполнения. Таким образом, упрощенный совет состоит в том, чтобы вам было проще: «используйте параметризованные запросы SQL», «не используйте eval».
Возьмем ваш пример эффектов заклинаний: одно дело встроить компилятор или интерпретатор Lua в вашу игру, чтобы позволить игровым дизайнерам более простой язык, чем C ++ (или любой другой), для описания эффектов заклинаний. Большинство «проблем eval» не применимы, если все, что вы делаете, - это оценка кода, который был написан и протестирован и включен в игру, DLC или что-то еще. Это просто смешение языков. Большие проблемы возникают у вас, когда вы пытаетесь сгенерировать Lua (или C ++, или SQL, или команды оболочки, или что-то еще) на лету и все испортить.
источник
Нет, очевидного исторического факта нет.
Зла Эвала очевидны с самого начала. Другие функции слегка опасны. Люди могут удалять данные. Люди могут видеть данные, которые они не должны. Люди могут писать данные, которые они не должны. И они могут делать большинство этих вещей, только если вы как-то облажаетесь и не проверяете пользовательский ввод.
С помощью eval они могут взломать пятиугольник и сделать так, как будто вы это сделали. Они могут проверять нажатия клавиш, чтобы получить ваши пароли. Предполагая полный язык Тьюринга, они могут буквально делать все, что способен ваш компьютер.
И вы не можете подтвердить ввод. Это произвольная строка произвольной формы. Единственный способ проверить это - создать анализатор и механизм анализа кода для данного языка. Желаем удачи в этом.
источник
Я думаю, что это сводится к следующим аспектам:
Необходимость
Я пытаюсь сказать следующее: вам нужно читать / писать почти для основных инструментов. То же самое для хранения высоких результатов вашей о-о-такой удивительной игры.
Без чтения / записи ваш графический редактор бесполезен. Без
eval
? Я напишу вам специальный плагин для этого!(Охраняемый) Использование
Многие методы могут быть потенциально опасными. Как, например,
read
иwrite
. Типичным примером является веб-сервис, позволяющий читать изображения из определенного каталога, указав имя. Однако «имя» на самом деле может быть любым допустимым (относительным) путем в системе, что позволяет вам читать все файлы, к которым имеет доступ веб-служба, а не только изображения. Злоупотребление этим простым примером называется «обход пути». Если ваше приложение разрешает обход пути, это плохо. Аread
без защиты от прохождения пути вполне можно назвать злом.Однако в других случаях строка для
read
полностью находится под контролем программистов (может быть, жестко закодирована?). В этом случае это вряд ли зло, чтобы использоватьread
.Доступ
Теперь еще один простой пример использования
eval
.Где-то в вашем веб-приложении вам нужен динамический контент. Вы позволите администраторам вводить некоторый код, который является исполняемым. Поскольку администраторы являются доверенными пользователями, теоретически это может быть нормально. Просто убедитесь, что не выполняете код, отправленный не администраторами, и все в порядке.
(То есть, пока вы не уволили этого милого администратора, но забыли отозвать его доступ. Теперь ваше веб-приложение уничтожено).
Проверяемость.
Думаю, еще один важный аспект заключается в том, насколько легко проверить вводимые пользователем данные.
Используя пользовательский ввод в вызове чтения? Просто убедитесь (очень), что входные данные для вызова read не содержат ничего вредоносного. Нормализуйте путь и убедитесь, что открываемый файл находится в вашем медиа-каталоге. Теперь это безопасно.
Пользовательский ввод при записи вызова? Такой же!
SQL-инъекция? Просто избегайте его или используйте параметризованные запросы, и вы в безопасности.
Eval? Как вы собираетесь проверить ввод, который используется для
eval
вызова? Вы можете работать очень усердно, но действительно очень сложно (если не невозможно) заставить его работать надежно.Многоступенчатые атаки
Теперь, каждый раз, когда вы используете пользовательский ввод, вам нужно взвесить преимущества его использования против опасностей. Защищайте его использование как можно больше.
Рассмотрим еще раз
eval
способные вещи в примере администратора. Я сказал вам, что все в порядке.Теперь учтите, что на самом деле в вашем веб-приложении есть место, где вы забыли скрыть пользовательский контент (HTML, XSS). Это меньшее преступление, чем доступный пользователю eval. Но, используя неэкранированный пользовательский контент, пользователь может получить
eval
доступ к веб-браузеру администратора и добавить способный большой двоичный объект через сеанс администратора, предоставляя снова полный доступ к системе.(Та же самая многоэтапная атака может быть сделана с помощью SQL-инъекции вместо XSS, или некоторые произвольные файловые записи заменяют исполняемый код вместо использования
eval
)источник
eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder")
. Проверка того, что ввод является буквенно-цифровым, возможна. Кроме того, «делает ли это остановкой» ортогонально «делает ли он изменение / доступ к состоянию, к которому он не должен прикасаться» и «выполняет ли он методы, которые он не должен вызывать».Чтобы эта функция работала вообще, это означает, что мне нужно держать слой отражения вокруг, который обеспечивает полный доступ ко внутреннему состоянию всей программы.
Для интерпретируемых языков я могу просто использовать состояние интерпретатора, что легко, но в сочетании с JIT-компиляторами это все еще значительно увеличивает сложность.
Без
eval
этого JIT-компилятор часто может доказать, что к локальным данным потока нет доступа из какого-либо другого кода, поэтому вполне приемлемо изменить порядок доступа, исключить блокировки и кешировать часто используемые данные в течение более длительного времени. Когда другой поток выполняетeval
оператор, может потребоваться синхронизировать выполняемый JIT-скомпилированный код с этим, поэтому внезапно сгенерированный JIT-код нуждается в механизме возврата, который возвращается к неоптимизированному выполнению в течение разумного периода времени.Этот тип кода имеет тенденцию иметь много тонких, трудно воспроизводимых ошибок, и в то же время он также накладывает ограничение на оптимизацию в JIT-компиляторе.
Для скомпилированных языков компромисс еще хуже: большинство оптимизаций запрещено, и мне нужно хранить обширную символьную информацию и интерпретатора, поэтому дополнительная гибкость, как правило, не стоит - часто проще определить интерфейс для некоторого внутреннего структуры, например, давая скриптовое представление и контроллер параллельного доступа к программе по модели .
источник
Я отвергаю предпосылку, которая
eval
считается более злой, чем арифметика указателей, или более опасной, чем прямой доступ к памяти и файловой системе. Я не знаю ни одного разумного разработчика, который бы поверил в это. Кроме того, языки, поддерживающие арифметику с указателем / прямой доступ к памяти, обычно не поддерживаютeval
и наоборот, поэтому я уверен, что такое сравнение было бы уместно.Но это
eval
может быть более известная уязвимость по той простой причине, что она поддерживается JavaScript. JavaScript является изолированным языком без прямого доступа к памяти или файловой системе, поэтому у него просто нет этих уязвимостей, за исключением слабых мест в самой реализации языка.Eval
поэтому является одной из самых опасных функций языка, так как открывает возможность произвольного выполнения кода. Я считаю, что на JavaScript разрабатывается гораздо больше разработчиков, чем на C / C ++, поэтомуeval
для большинства разработчиков просто важнее знать об этом, чем переполнение буфера.источник
Ни один серьезный программист не посчитал бы, что Eval - «зло». Это просто инструмент программирования, как и любой другой. Страх (если есть страх) этой функции не имеет ничего общего с массовой культурой. Это просто опасная команда, которая часто используется неправильно и может привести к серьезным пробелам в безопасности и ухудшить производительность. Исходя из собственного опыта, я бы сказал, что редко встречается проблема программирования, которая не может быть решена более безопасно и эффективно другими способами. Программисты, которые чаще всего используют eval, - это те, кто, вероятно, менее квалифицирован, чтобы делать это безопасно.
Сказав это, есть языки, где использование eval уместно. Perl приходит на ум. Однако я лично считаю, что это очень редко требуется в других, более современных языках, которые изначально поддерживают структурированную обработку исключений.
источник
Я думаю, что вы достаточно хорошо освещаете это в следующей части вашего вопроса (выделение мое):
Для 95%, которые могли бы использовать это правильно, все это хорошо; но всегда найдутся люди, которые не используют его должным образом. Некоторые из них будут из-за неопытности и недостатка способностей, остальные будут злонамеренными.
Всегда найдутся люди, которые хотят раздвинуть границы и найти дыры в безопасности - некоторые во благо, некоторые во вред.
Что касается исторического аспекта этого факта,
eval
функции типов по существу позволяют выполнять произвольный код, который ранее использовался в популярной веб-CMS, Joomla! , С Joomla! поддержка более 2,5 миллионов сайтов по всему миру - это большой потенциальный ущерб не только посетителям этих сайтов, но и потенциально инфраструктуре, на которой он размещен, а также репутации сайтов / компаний, которые были использованы.Joomla! Пример может быть простым, но он был записан.
источник
Есть несколько веских причин препятствовать использованию
eval
(хотя некоторые специфичны для определенных языков).eval
часто, удивляет (то есть, вы думаете, чтоeval(something here)
нужно делать одно, а делать другое, возможно, вызывать исключения).Лично я бы не стал даже говорить, что это зло, но я всегда буду оспаривать использование
eval
в обзоре кода с формулировками в духе «Вы рассматривали какой-то код здесь ?» (если у меня будет время сделать хотя бы предварительную замену), или "вы уверены, что eval действительно является лучшим решением здесь?" (если я не сделаю).источник
В главе 6.4 « Общества разума Мински» он говорит:
Когда одна программа (B) пишет другую программу (A), она функционирует как метапрограмма. Предмет B - программа A.
Есть программа на Си. Это тот, кто в вашей голове пишет программу B.
Опасность в том, что может быть кто-то (C ') со злым умыслом, который может вмешиваться в этот процесс, поэтому вы получаете такие вещи, как SQL-инъекция.
Задача состоит в том, чтобы сделать программное обеспечение умнее, не делая его еще более опасным.
источник
У вас здесь много хороших ответов, и главная причина состоит в том, что выполнение произвольного кода плохо, но я добавлю еще один фактор, который другие затронули только на грани:
Это действительно трудно исправить код , который в настоящее время оценивается из текстовой строки. Ваши обычные инструменты отладки в значительной степени прямо из окна, и вы сводитесь к отслеживанию старой школы или эхо. Очевидно, что это не имеет большого значения, если у вас есть фрагмент в одной строке, который вы хотите,
eval
но, как опытный программист, вы, вероятно, можете найти лучшее решение для этого, в то время как крупномасштабная генерация кода может быть где-то, что функция оценки становится потенциально полезным союзником.источник