Я пишу некоторый код JavaScript для анализа введенных пользователем функций (для работы с таблицами). Разобрав формулу, я смог преобразовать ее в JavaScript и запустить eval()
на ней, чтобы получить результат.
Тем не менее, я всегда уклонялся от использования, eval()
если я могу избежать этого, потому что это зло (и, правильно или неправильно, я всегда думал, что это еще более зло в JavaScript, потому что код, который должен быть оценен, может быть изменен пользователем ).
Итак, когда можно использовать его?
javascript
coding-style
eval
Ричард Тернер
источник
источник
Ответы:
Я хотел бы воспользоваться моментом, чтобы рассмотреть предпосылку вашего вопроса - это eval () - " зло ". Слово « зло », используемое людьми на языке программирования, обычно означает «опасный», или, точнее, «способный причинить много вреда простой командой». Итак, когда можно использовать что-то опасное? Когда вы знаете, в чем опасность, и когда вы принимаете соответствующие меры предосторожности.
Кстати, давайте посмотрим на опасности при использовании eval (). Вероятно, есть много небольших скрытых опасностей, как и все остальное, но есть два больших риска - причина, по которой eval () считается злом - это производительность и внедрение кода.
На ваш конкретный случай. Насколько я понимаю, вы сами генерируете строки, поэтому, если вы будете осторожны, чтобы не генерировать строку типа "rm -rf что-то важное", нет риска внедрения кода (но, пожалуйста, помните, это очень Трудно обеспечить это в общем случае). Кроме того, если вы работаете в браузере, то внедрение кода представляет собой довольно незначительный риск, я считаю.
Что касается производительности, вам придется сравнить ее с простотой кодирования. По моему мнению, если вы анализируете формулу, вы можете также вычислить результат во время анализа, а не запускать другой анализатор (тот, что внутри eval ()). Но это может быть проще для кода с использованием eval (), и снижение производительности, вероятно, будет незаметным. Похоже, что eval () в этом случае не более злой, чем любая другая функция, которая может сэкономить вам время.
источник
eval()
с вашего сервера, он также может в первую очередь просто изменить источник страницы, а также взять под контроль информацию пользователя. , , Я не вижу разницы.eval()
не зло Или, если это так, это зло так же, как отражение, файловый / сетевой ввод / вывод, многопоточность и IPC являются «злыми» в других языках.Если для вашей цели ,
eval()
быстрее , чем ручная интерпретация, или делают ваш код более простым, или более понятно ... то вы должны использовать его. Если ни то, ни другое Просто как тот.источник
Когда вы доверяете источнику.
В случае JSON более или менее сложно вмешаться в источник, потому что он исходит от веб-сервера, которым вы управляете. Пока сам JSON не содержит данных, загруженных пользователем, нет существенного недостатка в использовании eval.
Во всех других случаях я бы сделал все возможное, чтобы пользовательские данные соответствовали моим правилам, прежде чем передавать их в eval ().
источник
eval
также не будет правильно анализировать все допустимые строки JSON. Например,JSON.parse(' "\u2028" ') === "\u2028"
ноeval(' "\u2028" ')
вызывает исключение, потому что U + 2028 - это новая строка в JavaScript, но это не новая строка в отношении JSON.Давайте настоящие люди:
Каждый крупный браузер теперь имеет встроенную консоль, которую ваш потенциальный хакер может использовать в изобилии для вызова любой функции с любым значением - зачем им пытаться использовать оператор eval - даже если они могут?
Если для компиляции 2000 строк JavaScript требуется 0,2 секунды, какова будет моя производительность, если я получу четыре строки JSON?
Даже объяснение Крокфорда «зло - это зло» слабо.
Как мог бы сам Крокфорд сказать: «Такое утверждение порождает иррациональный невроз. Не покупайте его».
Понимание eval и знание того, когда это может быть полезно, гораздо важнее. Например, eval - это разумный инструмент для оценки ответов сервера, сгенерированных вашим программным обеспечением.
Кстати: Prototype.js вызывает eval напрямую пять раз (в том числе в evalJSON () и evalResponse ()). jQuery использует его в parseJSON (через конструктор функций).
источник
Я склонен следовать советам Крокфорда в для
eval()
, и избежать его полностью. Даже способы, которые, кажется, требуют этого, не делают. Например,setTimeout()
позволяет вам передавать функцию, а не Eval.Даже если это надежный источник, я не использую его, потому что код, возвращаемый JSON, может быть искажен, что в лучшем случае может сделать что-то нехорошее, а в худшем - показать что-то плохое.
источник
Я видел, как люди выступают за то, чтобы не использовать eval, потому что это зло , но я видел, как те же люди динамически используют Function и setTimeout, поэтому они используют eval под капотами : D
Кстати, если ваша песочница недостаточно уверена (например, если вы работаете на сайте, где разрешено внедрение кода), eval - это последняя из ваших проблем. Основное правило безопасности заключается в том, что все вводимые данные являются злыми, но в случае JavaScript даже сам JavaScript может быть злым, поскольку в JavaScript вы можете перезаписать любую функцию и просто не можете быть уверены, что используете настоящую, поэтому если вредоносный код запускается раньше вас, вы не можете доверять любой встроенной функции JavaScript: D
Теперь эпилог к этому посту:
Если вам ДЕЙСТВИТЕЛЬНО это нужно (80% времени eval НЕ требуется) и вы уверены в том, что делаете, просто используйте eval (или лучшую функцию;)), затворы и ООП покрывают 80/90% случай, когда eval может быть заменен с использованием другой логики, остальное - это динамически генерируемый код (например, если вы пишете интерпретатор) и, как вы уже сказали, оценка JSON (здесь вы можете использовать безопасную оценку Крокфорда;))
источник
Eval дополняет компиляцию, которая используется в шаблонах кода. Под шаблонизацией я подразумеваю, что вы пишете упрощенный генератор шаблонов, который генерирует полезный код шаблона, который увеличивает скорость разработки.
Я написал фреймворк, в котором разработчики не используют EVAL, но они используют наш фреймворк, и, в свою очередь, этот фреймворк должен использовать EVAL для генерации шаблонов.
Производительность EVAL может быть увеличена с помощью следующего метода; вместо выполнения сценария вы должны вернуть функцию.
Это должно быть организовано как
Кеширование f, безусловно, улучшит скорость.
Также Chrome позволяет легко отлаживать такие функции.
Что касается безопасности, использование eval или нет вряд ли будет иметь значение,
Если ваша серверная безопасность достаточно надежна, чтобы кто-то мог атаковать откуда угодно, вам не стоит беспокоиться о EVAL. Как я уже упоминал, если EVAL не существует, у злоумышленников есть много инструментов для взлома вашего сервера независимо от возможностей EVAL вашего браузера.
Eval хорош только для генерации некоторых шаблонов для выполнения сложной обработки строк на основе чего-то, что не используется заранее. Например, я предпочту
В отличие от
Как мое отображаемое имя, которое может исходить из базы данных и не является жестко закодированным.
источник
function (first, last) { return last + ' ' + first }
.eval
основном других пользователей . Допустим, у вас есть страница настроек, и она позволяет вам установить, как ваше имя будет выглядеть для других. Скажем также, что вы не очень четко думали, когда писали это, поэтому в вашем окне выбора есть такие параметры, как<option value="LastName + ' ' + FirstName">Last First</option>
. Я открываю инструменты разработчика, изменяюvalue
опцию наalert('PWNED!')
, выбираю измененную опцию и отправляю форму. Теперь, когда кто-то другой увидит мое отображаемое имя, этот код запускается.eval
том, чтобы выполнить код, который не является частью написанного вами сценария. Если вам не нужна сила для этого (а вы почти никогда не делаете этого), избеганиеeval
помогает избежать целой категории проблем. Это хорошо, если ваш серверный код не идеален.При отладке в Chrome (v28.0.1500.72) я обнаружил, что переменные не связаны с замыканиями, если они не используются во вложенной функции, которая создает замыкание. Я думаю, это оптимизация движка JavaScript.
НО : когда
eval()
используется внутри функции, которая вызывает замыкание, ВСЕ переменные внешних функций привязываются к замыканию, даже если они вообще не используются. Если у кого-то есть время, чтобы проверить, могут ли утечки памяти быть вызваны этим, пожалуйста, оставьте мне комментарий ниже.Вот мой тестовый код:
Здесь я хотел бы отметить, что eval () не обязательно должен ссылаться на нативную
eval()
функцию. Все зависит от названия функции . Таким образом, при вызове нативаeval()
с псевдонимом (скажем,var noval = eval;
а затем во внутренней функцииnoval(expression);
) тогда оценкаexpression
может потерпеть неудачу, когда она ссылается на переменные, которые должны быть частью замыкания, но на самом деле это не так.источник
Microsoft объясняет, почему eval () работает медленно в их браузере, в блоге IE, рекомендации по производительности IE + JavaScript, часть 2. Неэффективность кода JavaScript .
источник
Нижняя граница
Если вы создали или санировали свой код
eval
, это никогда не было злом .Чуть подробнее
eval
это зло , если работают на сервере , используя вход , представленный клиентом , который не создал разработчик или что было не продезинфицировать разработчик .eval
это не зло , если он выполняется на клиенте, даже при использовании unsanitized ввода созданного клиента .Очевидно, что вы всегда должны очищать входные данные, чтобы иметь некоторый контроль над тем, что потребляет ваш код.
аргументация
Клиент может выполнить любой произвольный код, который он хочет, даже если разработчик не кодировал его; Это верно не только для того, что уклоняется, но и призыв к
eval
себе .источник
Единственный случай, когда вы должны использовать eval (), это когда вам нужно запускать динамический JS на лету. Я говорю о JS, который вы загружаете асинхронно с сервера ...
... И 9 раз из 10 вы можете легко избежать этого путем рефакторинга.
источник
eval
редко является правильным выбором. В то время как могут быть многочисленные случаи, когда вы можете выполнить то, что вам нужно, объединяя сценарий и выполняя его на лету, в вашем распоряжении обычно гораздо более мощные и поддерживаемые методы: нотация ассоциативного массива (obj["prop"]
такая же, какobj.prop
) , замыкания, объектно-ориентированные методы, функциональные методы - используйте их вместо этого.источник
Что касается клиентского сценария, я думаю, что вопрос безопасности является спорным. Все, что загружено в браузер, подвергается манипуляциям и должно рассматриваться как таковое. Использование оператора eval () практически исключает риск, когда есть гораздо более простые способы выполнения кода JavaScript и / или манипулирования объектами в DOM, такими как строка URL в вашем браузере.
Если кто-то хочет манипулировать своим DOM, я говорю: откажитесь. Безопасность для предотвращения любого типа атаки всегда должна быть ответственностью серверного приложения, точка.
С прагматической точки зрения нет смысла использовать eval () в ситуации, когда все можно сделать иначе. Тем не менее, есть конкретные случаи, когда следует использовать eval. Когда это так, это определенно можно сделать без риска взорвать страницу.
источник
<head></head>
требуется, даже если пусто?На стороне сервера eval полезен при работе с внешними сценариями, такими как sql или influenxdb или mongo. Там, где пользовательская проверка во время выполнения может быть выполнена без повторного развертывания ваших служб.
Например, служба достижений со следующими метаданными
Которые затем позволяют,
Прямая инъекция объекта / значений через буквальную строку в формате json, полезная для шаблонных текстов
Можно использовать в качестве компаратора, скажем, мы устанавливаем правила, как проверять квест или события в CMS
Против этого:
Могут быть ошибки в коде и поломка вещей в сервисе, если они не полностью протестированы.
Если хакер может написать скрипт в вашей системе, то вы в значительной степени облажались.
Один из способов проверки вашего скрипта - хранить хеш ваших скриптов где-нибудь в безопасности, чтобы вы могли проверить их перед запуском.
источник
Я думаю, что любые случаи оправданности eval были бы редкостью. Вы, скорее всего, будете использовать его, думая, что это оправдано, чем использовать его, когда это на самом деле оправдано.
Вопросы безопасности являются наиболее известными. Но также имейте в виду, что JavaScript использует JIT-компиляцию, и это плохо работает с eval. Eval чем-то напоминает «черный ящик» для компилятора, и JavaScript должен уметь предсказывать код заранее (до некоторой степени), чтобы безопасно и правильно применять оптимизацию производительности и область видимости. В некоторых случаях влияние на производительность может даже повлиять на другой код за пределами eval.
Если вы хотите узнать больше: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval
источник
Это нормально, если вы имеете полный контроль над кодом, который передается
eval
функции.источник
eval
, то возникает большой вопрос, когда имеет смысл, чтобы это была строка, а не реальный JS?<script async="true" src="...">
. Смотрите также: w3bits.com/async-javascriptТолько во время тестирования, если это возможно. Также обратите внимание, что eval () намного медленнее, чем другие специализированные оценщики JSON и т. Д.
источник
Нет причин не использовать eval (), если вы можете быть уверены, что источник кода исходит от вас или от реального пользователя. Несмотря на то, что он может манипулировать тем, что отправляется в функцию eval (), это не проблема безопасности, поскольку он может манипулировать исходным кодом веб-сайта и поэтому может изменить сам код JavaScript.
Итак ... когда не следует использовать eval ()? Eval () не должен использоваться, только когда есть вероятность, что третье лицо может изменить его. Например, перехватить соединение между клиентом и вашим сервером (но если это проблема, используйте HTTPS). Вы не должны использовать eval () для анализа кода, написанного другими людьми, как на форуме.
источник
eval
отношение к строке, составленной из содержимого одного пользователя, может позволить этому пользователю выполнять код в браузере другого пользователя.eval
ее видит . Так происходит все время.eval
. Чем полезно винить сервер? Если кто-то должен быть обвинен, это должен быть нападающий. Независимо от вины, клиент, который не уязвим для XSS, несмотря на ошибки на сервере, лучше, чем клиент, который уязвим при прочих равных условиях.Если это действительно нужно, eval - это не зло. Но 99,9% случаев использования eval, с которыми я сталкиваюсь, не нужны (не считая setTimeout).
Для меня зло - это не производительность или даже проблема безопасности (ну, косвенно, это и то и другое). Все такие ненужные использования eval добавляют к адскому обслуживанию. Инструменты рефакторинга скинуты. Искать код сложно. Непредвиденные последствия этих уловок легион.
источник
Когда eval () JavaScript не является злом?
Я всегда пытаюсь отговорить от использования eval . Почти всегда доступно более чистое и удобное решение. Eval не нужен даже для анализа JSON . Eval добавляет в ад обслуживания . Недаром его осуждают такие мастера, как Дуглас Крокфорд.
Но я нашел один пример, где его следует использовать:
Когда вам нужно передать выражение.
Например, у меня есть функция , которая строит общий
google.maps.ImageMapType
объект для меня, но я должен сказать ему рецепт, как он должен построить URL плитки изzoom
иcoord
параметров:источник
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Мой пример использования
eval
: импорт .Как это обычно делается.
Но с помощью
eval
небольшой вспомогательной функции он выглядит намного лучше:importable
может выглядеть так (эта версия не поддерживает импорт конкретных элементов).источник
.replace(/name/g, name).replace('path', path)
. Еслиname
содержит строку,"path"
то вы можете получить сюрпризы.components
является возможным запахом кода; рефакторинг вашего кода может полностью устранить «проблему». Ваше текущее решение - просто синтаксический сахар. Если вы настаиваете на этом, я бы порекомендовал написать собственный препроцессор, который будет выполнен перед развертыванием. Это должно держатьсяeval
подальше от производственного кода.Эвал не злой, просто неправильно
Если вы создали код, входящий в него, или можете доверять ему, все в порядке. Люди продолжают говорить о том, что пользовательский ввод не имеет значения с eval. Ну вроде ~
Если есть пользовательский ввод, который отправляется на сервер, затем возвращается к клиенту, и этот код используется в eval без очистки. Поздравляю, вы открыли ящик Пандоры для отправки пользовательских данных кому бы то ни было.
В зависимости от того, где находится eval, многие веб-сайты используют SPA, и eval может упростить пользователю доступ к внутренним компонентам приложения, что в противном случае было бы нелегко. Теперь они могут создать поддельное расширение для браузера, которое может записывать данные в eval и снова красть данные.
Просто должен понять, какой смысл использовать Eval. Генерация кода на самом деле не идеальна, когда вы можете просто создавать методы для таких вещей, использовать объекты или тому подобное.
Теперь хороший пример использования eval. Ваш сервер читает файл swagger, который вы создали. Многие из параметров URL создаются в формате
{myParam}
. Таким образом, вы хотите прочитать URL-адреса, а затем преобразовать их в строки шаблона без необходимости выполнять сложные замены, поскольку у вас много конечных точек. Таким образом, вы можете сделать что-то вроде этого. Обратите внимание, что это очень простой пример.источник
Генерация кода. Недавно я написал библиотеку под названием Hyperbars, которая ликвидирует разрыв между виртуальным домом и рулем . Это делается путем анализа шаблона руля и преобразования его в гиперскрипт . Гиперскрипт сначала генерируется в виде строки, а перед возвращением
eval()
превращается в исполняемый код. я нашелeval()
в этой конкретной ситуации полную противоположность зла.В основном из
К этому
Производительность
eval()
не является проблемой в подобной ситуации, потому что вам нужно только один раз интерпретировать сгенерированную строку, а затем многократно использовать исполняемый вывод.Вы можете увидеть , как генерация кода было достигнуто , если вам интересно здесь .
источник
eval
намек на то, что некоторая ответственность, которая принадлежит во время компиляции, перешла во время выполнения.Я считаю, что eval - очень мощная функция для клиентских веб-приложений и безопасная ... Такая же безопасная, как и JavaScript, а это не так. :-) Проблемы безопасности, по сути, являются проблемой на стороне сервера, потому что теперь, с помощью такого инструмента, как Firebug, вы можете атаковать любое приложение JavaScript.
источник
eval
должно быть защищено от атак XSS, что не всегда легко сделать правильно.Eval полезен для генерации кода, когда у вас нет макросов.
Для (глупого) примера, если вы пишете компилятор Brainfuck , вы, вероятно, захотите создать функцию, которая выполняет последовательность инструкций в виде строки, и вычислить ее для возврата функции.
источник
eval
.eval
, когда альтернатива ( функция ) является одновременно более быстрой ( как описано в MDN ) и более надежной (предотвращает непредсказуемые ошибки благодаря лучшей изоляции между сгенерированным кодом и другим «вспомогательным» кодом на той же веб-странице).Когда вы анализируете структуру JSON с помощью функции синтаксического анализа (например, jQuery.parseJSON), она ожидает идеальную структуру файла JSON (каждое имя свойства в двойных кавычках). Тем не менее, JavaScript является более гибким. Поэтому вы можете использовать eval (), чтобы избежать этого.
источник
eval
, особенно при получении данных JSON из стороннего источника. Смотрите JSON.Stringify без кавычек на свойства? для правильного подхода к разбору "JSON без кавычек имен ключей".string
и определяет последовательностьstring
как ноль или более символов Unicode, заключенных в двойные кавычки, с использованием обратной косой черты.eval
. В любом серьезном мультитенантном веб-приложении с десятками разработчиков, работающих над одной и той же кодовой базой, это недопустимо.