Когда eval () в JavaScript не является злом?

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

Однако я всегда уклонялся от использования eval(), если я могу избежать этого, потому что это зло (и, правильно или ошибочно, я всегда думал, что это еще более зло в JavaScript, потому что код, который нужно оценить, может быть изменен Пользователь).

Итак, когда его можно использовать?

Большинство библиотек JSON фактически не используют eval под капотом именно для защиты от угроз безопасности.

Sean McMillan 14.12.2009 20:23

@Sean - и JQuery, и Prototype используют eval (JQuery использует его через новую функцию)

plodder 20.04.2010 02:53

@plodder - Откуда вы берете информацию? jQuery использует собственный JSON.parse () с версии 1.4 (еще в 1/2010)! Смотрите сами: code.jquery.com/jquery-1.4.js

ken 04.01.2011 21:38

@ ken, Шон, он использует JSON.parse если это доступно, это не так для IE <= 7

tobyodavies 27.01.2011 06:54

@tobyodavies - хороший аргумент, за исключением того, что IE <= 7 вводит в заблуждение, поскольку ЛЮБОЙ браузер старше нескольких лет не будет иметь собственного объекта JSON. и я хотел сказать, что библиотеки JS не поддерживают предпочитатьeval() .... это просто резерв для браузеров наследие.

ken 27.01.2011 07:52

@ken, тоже хороший аргумент, однако IE6 и IE7 все еще очень широко используются, я бы назвал их старыми, не уверен в наследии - они, к сожалению, далеки от мертвых. определенно они не предпочитают это, но они используют его в некоторых ситуациях, поэтому они считают, что это достаточно безопасно с некоторыми ограничениями.

tobyodavies 27.01.2011 08:35

Еще одно обсуждение этой темы, более ориентированное на javascript, находится на stackoverflow.com/questions/4812288/….

tobyodavies 28.01.2011 12:28
«Очевидно, для анализа JSON нужно использовать eval ()» -- this is not true, on the contrary - one не следует использовать eval для анализа JSON! Use Douglas Crockfords' (creator of JSON) json2.js script from json.org!
TMS 26.04.2012 03:47

@Tomas: ирония в том, что json2.js использует eval для анализа JSON

tobyodavies 08.06.2012 06:01

@tobyodavies, вау, это интересно, учитывая, что Дуглас критикует это. По крайней мере, есть серьезные проверки безопасности.

TMS 08.06.2012 11:08

@Tomas, +1. Фактически, вы не можете использовать eval для правильного анализа всех строк JSON. JSON.parse(' "\u2028" ') работает, но eval(' "\u2028" ') не работает с исключением, потому что U + 2028 является новой строкой JavaScript, но разрешен в JSON без экранирования.

Mike Samuel 04.08.2012 02:40

Использование eval может раскрыть код реализации вашей библиотеки, потому что он запускается из закрытия. Падение производительности также велико, потому что он каждый раз анализирует и компилирует. С конструктором Function этого можно избежать. Конструктор Function запускается при глобальном замыкании независимо от того, где он вызывается. Если вы планируете вызывать эту функцию несколько раз, она может стать «горячей», и движок JavaScript оптимизирует ее. И поскольку он возвращает объект функции, вы можете сохранить его в кеше, чтобы ограничить вызовы конструктора Function.

Plamen Dragiyski 21.12.2014 14:54

@tobyodavies Верно, однако Крокфорд говорит не используйте json2.js, если вам не нужна поддержка IE 8.

jkdev 15.04.2015 21:23

@jkdev Когда этот вопрос был задан, IE8 был доминирующим браузером, IE9 едва исполнился год. И Крокфорд добавил этот дискламер всего 2 недели назад (почти через 3 года после моего последнего комментария)

tobyodavies 20.04.2015 04:14

Вау, всего 2 недели назад? Я этого не знал.

jkdev 20.04.2015 19:34

Я понимаю точку зрения Крокфорда о рисках оценки вредоносного кода, встроенного в JSON. Как говорит @TMS, в json2.js есть проверки безопасности для защиты от этого.

jkdev 20.04.2015 19:38

@jkdev - по сути, вы пропустили, что Крокфорд говорит не использовать этот файл потому что JSON стал встроенной функцией JavaScript. AFAIK, в наши дни вы являются используете [эквивалентную функциональность]; но вы оставляете детали реализации на усмотрение поставщика языка.

ToolmakerSteve 15.02.2017 08:50

@ToolmakerSteve json2.js: Вы правы в том, что с точки зрения пользователя не имеет значения, как JSON.parse () реализован под капотом. IE8 не имеет встроенного объекта JSON, поэтому вы должны использовать json2.js Крокфорда как более безопасную альтернативу eval, использующему JSON в своем коде. Это почти все, что нужно сделать.

jkdev 15.02.2017 09:38

«анализировать введенные пользователем функции (для функциональности, подобной электронной таблице)» подсказывает мне, что большая часть озабоченности по поводу eval здесь необоснованна. Предположим, что функция не сохраняется в БД, какой вред может нанести функция javascript на уровне одностраничного пользователя? Взламывает собственные данные? Если сохраняется и не передается, опять же, проблема относится к пользователю. Сохраняются и передаются (или просматриваются другими), да, у вас есть вектор XSS-инъекции.

Jed Schneider 14.03.2018 21:31

eval всегда зло. Период исключений не существует. Если вы хотите оценить код, используйте window.Function. Конечно, есть случаи, когда вы можете делать с eval вещи, которые нельзя сделать иначе, но это незаконные варианты использования, которые никогда не должны выполняться каким-либо уважающим себя кодировщиком.

Jack Giffin 21.05.2018 23:30

Mozilla ясно дает понять: Никогда не используйте eval!

Ruud Helderman 14.07.2019 02:16

Не забывайте, что eval несовместим со всеми инструментами, которые вы можете придумать, ESLint, Prettier, UglifyJS, большинством редакторов / функций IDE ... и вашим коллегам это не понравится, если они будут профессиональными. Поиск хитрого способа сделать что-то может показаться умным для решения немедленной проблемы, но это не в долгосрочной перспективе.

Rivenfall 04.09.2020 02:27
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
276
22
92 252
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

Когда вы доверяете источнику.

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

Во всех остальных случаях я бы приложил все усилия, чтобы убедиться, что предоставленные пользователем данные соответствуют моим правилам, прежде чем передавать их в eval ().

Строку json всегда следует проверять на соответствие грамматике json, прежде чем использовать ее в eval (). Таким образом, строка json «{foo: alert ('XSS')}» не пройдет, поскольку «alert ('XSS')» не является правильным значением.

Gumbo 11.02.2009 15:52

Или когда среда безопасна.

Eli Grey 21.10.2009 04:30

Но можно ли действительно доверять источнику, если вы используете протокол, уязвимый для атак типа «злоумышленник в середине»?

Justin Johnson 15.12.2009 21:13

Что ж, тогда используйте HTTPS. OTOH: человек посередине не является типичным сценарием атаки для разнообразных веб-приложений, в отличие от межсайтового скриптинга.

Tomalak 15.12.2009 21:50

eval также не будет правильно анализировать все допустимые строки JSON. Например, JSON.parse(' "\u2028" ') === "\u2028", но eval(' "\u2028" ') вызывает исключение, потому что U + 2028 - это новая строка в JavaScript, но это не новая строка в отношении JSON.

Mike Samuel 04.08.2012 02:36

@Justin - если протокол скомпрометирован, ну, обычно начальная загрузка страницы будет отправлена ​​по тому же протоколу, и тогда это спорный вопрос, потому что клиент уже настолько скомпрометирован, насколько это возможно.

antinome 06.11.2013 22:38

Красиво сказано @Tomalak, я прямо сейчас упомянул об этом в своем ответе! Потрясающий!

NiCk Newman 01.08.2015 14:06

«В случае JSON более или менее сложно вмешаться в исходный код, потому что он исходит от веб-сервера, которым вы управляете». Если вы не создаете службу REST API в nodejs. И даже если вы контролируете ситуацию, вы вводите уязвимость, которая становится идеальной отправной точкой для «безопасных» пользовательских сеансов после того, как доверенный сервер окажется скомпрометированным. Хакеры преуспевают в такой наивности. К счастью, сейчас есть хорошие альтернативы eval.

Ruud Helderman 14.07.2019 23:20

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

Tomalak 17.07.2019 00:42

Единственный случай, когда вам следует использовать eval (), - это когда вам нужно запускать динамический JS на лету. Я говорю о JS, который вы загружаете асинхронно с сервера ...

... И 9 раз из 10 вы могли бы легко избежать этого путем рефакторинга.

В настоящее время существуют другие (и более совершенные) способы асинхронной загрузки JavaScript с сервера: w3bits.com/async-javascript

Ruud Helderman 14.07.2019 18:31

Его можно использовать, если у вас есть полный контроль над кодом, передаваемым функции eval.

Если у вас есть полный контроль над тем, что вы передаете на eval, тогда возникает большой вопрос, когда имеет смысл использовать строку, а не настоящий JS?

cHao 15.01.2014 17:59

@cHao Например, если у вас есть большое игровое приложение (5-10 МБ Javascript), лучше сначала создать простой быстро загружаемый AJAX-Preloader (1 КБ), который загружает большой основной скрипт при отображении файла Loading- Бар или что-то подобное. После загрузки вы можете использовать «eval (источник)» или лучше «новую функцию (источник)» для запуска загруженного сценария игрового приложения. Таким образом, пользователь может визуально увидеть, что Приложению требуется время для загрузки, пока игра не запустится. Без этого пользователь должен ждать загрузки всего приложения без какой-либо визуальной обратной связи.

SammieFox 11.04.2017 21:08

@SammieFox Есть другие (и лучшие) способы сделать это, в первую очередь <script async = "true" src = "...">. См. Также: w3bits.com/async-javascript

Ruud Helderman 14.07.2019 18:17

Ответ - опасный совет; слишком многие разработчики ложно чувствуют, что все под контролем. Совет делает имеет смысл для программного обеспечения, которое больше не поддерживается активно. Но такое программное обеспечение следует считать мертвым.

Ruud Helderman 14.07.2019 18:27

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

setTimeout(function() {
  alert('hi');
}, 1000);

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

Каким образом успешный вызов веб-сервера приведет к искаженному результату (несмотря на ошибки в коде веб-сервера, генерирующего JSON)?

Tomalak 13.10.2008 18:46

Я думаю, что ошибки в форматере JSON на стороне сервера, безусловно, являются проблемой. Зависит ли ответ сервера от любого текста, отправленного пользователем? Тогда вам нужно следить за XSS.

swilliams 13.10.2008 19:06

Если ваш веб-сервер не аутентифицирован через HTTPS, вы можете пострадать от какой-то атаки типа «человек посередине», когда другой хост перехватывает запрос и отправляет свои собственные данные.

Ben Combee 21.12.2008 03:18

Если кто-то может выполнить атаку «человек посередине», он легко сможет внедрить что угодно в ваши скрипты.

el.pescado 05.05.2010 21:11

Вы вообще не должны полагаться на свой код javascript ... Вы не полагаетесь ни на что, что работает на стороне клиента ... Если кто-то атакует "человек посередине", зачем ему связываться с вашими объектами json? Он может обслуживать вам другую веб-страницу и разные файлы js ...

Calmarius 01.07.2010 17:24

Мне лично не нравится аргумент «всегда есть другие способы сделать это». Например, вы также можете сказать, что всегда есть способы избежать объектно-ориентированного программирования. Это не значит, что это не лучший вариант. Если вы понимаете eval и его опасности, он может стать отличным инструментом для использования в правильных ситуациях.

dallin 13.05.2013 22:20

Как можно было бы написать что-то вроде редактора "Tryit" на w3schools, Stack Snippets и т. д. Без eval?

Damian Yerrick 12.05.2019 01:58

Только во время тестирования, если возможно. Также обратите внимание, что eval () намного медленнее, чем другие специализированные оценщики JSON и т. д.

eval() - это не зло. Или, если это так, это зло так же, как отражение, файловый / сетевой ввод-вывод, многопоточность и IPC являются «злом» в других языках.

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

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

wberry 25.03.2014 19:39

Это настолько общий совет, что его можно применить буквально к любому существующему блоку кода. На самом деле это ничего не добавляет к этому вопросу; в частности, это не помогает никому, приходящему сюда, определять, является ли их конкретное использование проблематичным или нет.

jpmc26 04.10.2016 21:29

Быстрее, проще, понятнее ... Этот ответ недостаточно хорошо описывает последствия для безопасности.

Ruud Helderman 14.07.2019 23:28

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

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

Re: «Нет причин не использовать eval (), если вы можете быть уверены, что источник кода исходит от вас или от реального пользователя». Это предполагает, что есть один пользователь. Эта предпосылка не указана в ОП. Когда есть несколько пользователей, небрежный eval строки, составленной из содержимого одного пользователя, может позволить этому пользователю выполнить код в браузере другого пользователя.

Mike Samuel 04.08.2012 02:33

@MikeSamuel, eval может выполнять код в браузере другого пользователя, я этого не слышал, вы пробовали это? Такого никогда не случалось в истории просмотра, вы можете показать нам пример?

Akash Kava 19.04.2013 14:20

@AkashKava, строка может исходить от одного пользовательского агента, храниться в базе данных, а затем передаваться другому браузеру, который ее использует eval. Так происходит все время.

Mike Samuel 19.04.2013 19:10

@MikeSamuel база данных? где? кто обслуживает неправильную строку? Разве не виновата база данных на стороне сервера? Во-первых, EVAL не виноват в плохо написанном коде на стороне сервера. Используйте jsfiddle и покажите миру реальный пример, где он может причинить вред.

Akash Kava 19.04.2013 20:10

@AkashKava, я не понимаю твой вопрос. Мы не говорим о конкретном приложении, но о причинах не использовать eval. Насколько полезно винить сервер? Если кого и следует винить, так это злоумышленника. Независимо от вины, клиент, который не уязвим для XSS, несмотря на ошибки на сервере, лучше, чем клиент, который уязвим, при прочих равных.

Mike Samuel 19.04.2013 20:18

@AkashKava Вам может понадобиться eval для делать jsfiddle.

Damian Yerrick 12.05.2019 02:01

«Нет причин ...» Неправильно. Этот ответ игнорирует производительность и ремонтопригодность.

Ruud Helderman 14.07.2019 00:42
Ответ принят как подходящий

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

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

  • Производительность - eval () запускает интерпретатор / компилятор. Если ваш код скомпилирован, то это большой успех, потому что вам нужно вызвать возможно тяжелый компилятор в середине времени выполнения. Однако JavaScript по-прежнему в основном интерпретируемый язык, а это означает, что вызов eval () в общем случае не сильно снижает производительность (но см. Мои конкретные замечания ниже).
  • Внедрение кода - eval () потенциально запускает строку кода с повышенными привилегиями. Например, программа, работающая как администратор / root, никогда не захочет вводить данные пользователя eval (), потому что этот ввод потенциально может быть «rm -rf / etc / important-file» или хуже. Опять же, у JavaScript в браузере такой проблемы нет, потому что программа в любом случае работает под собственной учетной записью пользователя. Эта проблема может быть у серверного JavaScript.

К твоему конкретному случаю. Насколько я понимаю, вы сами генерируете строки, поэтому, предполагая, что вы осторожны, чтобы не допустить генерации такой строки, как "rm -rf something-important", риск внедрения кода отсутствует (но помните, что очень очень сложно для обеспечить это в общем случае). Кроме того, я считаю, что если вы работаете в браузере, внедрение кода представляет собой довольно незначительный риск.

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

Вы не решаете проблему кода, в котором используется eval, который трудно отлаживать.

bobobobo 29.08.2009 22:45

Более полный ответ на этот вопрос есть здесь stackoverflow.com/questions/951373/when-is-eval-evil-in-php

bobobobo 29.08.2009 22:46

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

Sean McMillan 14.12.2009 20:19

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

Razor 04.03.2010 08:38

@ Шон Макмиллан: Я хочу верить вам, но если кто-то собирается перехватить и изменить javascript, идущий на eval() с вашего сервера, он также может просто изменить источник страницы, а также взять под контроль информацию пользователя. . . Я не вижу разницы.

Walt W 01.04.2010 21:25

@ user27476 - Я согласен с тем, что если кто-то собирается анализировать строку, то можно продолжить и произвести вычисления. Я бы так поступил, но, может быть, это только я.

Pete Wilson 13.01.2012 01:36

В Chrome вот некоторые сравнения производительности между прямым кодом, уровнем этого кода и Function (code) () (то же, что и eval): jsperf.com/eval-vs-parse-and-call/2

Devin Rhode 08.04.2012 12:19

Re "Внедрение кода - ... Опять же, у JavaScript в браузере такой проблемы нет" и "Кроме того, если вы работаете в браузере, я считаю, что внедрение кода представляет собой довольно незначительный риск". Вы предлагаете, чтобы внедрение кода в браузере не было проблемой? XSS входит в топ-3 уязвимостей в топ-10 списка OWASP несколько лет подряд.

Mike Samuel 04.08.2012 02:42

@MikeSamuel, XSS работает только в том случае, если вы можете внедрить код в чужой браузер («Межсайтовый скриптинг (XSS) - это тип уязвимости компьютерной безопасности…, который позволяет злоумышленникам внедрять клиентский скрипт в веб-страницы, просматриваемые другими пользователями». Википедия) . Так что, если вы оцениваете код, который пользователь ввел на той же странице, ни вреда, ни фола. Если вы позволяете посетителям оставлять комментарии без предварительной обработки, вы открываете им возможность оставлять яйца кукушки.

thirdender 30.08.2012 19:18

@thirdender, что заставляет вас поверить, что строка, достигающая eval, не содержит символов, контролируемых другим пользователем? В исходном вопросе никогда не говорится, что электронную таблицу может просматривать только один пользователь.

Mike Samuel 30.08.2012 20:10

@MikeSamuel, каждый случай нужно рассматривать отдельно. Вот почему я сказал, что важно дезинфицировать вводимые пользователем данные. Однако я считаю, что фраза «eval - это зло» сама по себе не соответствует действительности. Однако, если вы оказались в ситуации, когда считаете, что eval - ваше единственное решение, вам следует остановиться и подумать. Если этого можно избежать, вероятно, лучше сделать это, но не любой ценой. Кроме того, стоит отметить, что Дуглас Крокфорд (известный как «eval is evil») осуждает безблочные операторы, а операнды ++ / -- только на две страницы после eval (Javascript: хорошие моменты).

thirdender 30.08.2012 23:39

@thirdender, я думаю, вы меня путаете с кем-то, кто сказал: "eval - это зло".

Mike Samuel 30.08.2012 23:50

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

akkishore 27.12.2012 12:31

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

Mike 08.04.2015 20:14

@bobobobo: на самом деле eval() может помочь в отладке. Мой пост под stackoverflow.com/questions/197769/…

Benjamin 19.09.2016 14:20

При внедрении кода: связанный с этим риск зависит от того, как именно используется функция eval. eval("alert('hello')") представляет собой не больший риск, чем alert('hello'), потому что в обоих случаях злоумышленнику потребуется изменить источник, чтобы что-то изменить. Однако если что-то вроде eval ("users ['" + username + "']") может быть чрезвычайно опасным, потому что злоумышленнику просто нужно придумать умное имя пользователя, и он сможет запускать код от имени других пользователей. tl; dr eval - это не зло. eval + плохое программирование - это зло.

Samy Bencherif 27.11.2016 23:25

«У JavaScript в браузере нет такой проблемы, потому что программа в любом случае выполняется под собственной учетной записью пользователя». Если только в JavaScript не указано «установить это вредоносное ПО на машину» и у пользователя есть на это права.

jpmc26 19.04.2017 07:30

У меня есть приложение только для внутреннего использования, в котором я подумал об использовании eval () для создания функций на основе предоставленного мной файла JSON. Функции влияют только на включение, обнуление и т. д. Полей пользовательского интерфейса, поэтому даже если JSON будет скомпрометирован, это приведет к поломке пользовательского интерфейса. Если они также изменят файл .js, то у них уже будет полный контроль. Было бы намного меньше кода ... Оглядываясь назад, я должен был это сделать.

Jonathan Rys 03.11.2017 02:02

Производительность: вы можете просто заставить eval создать функцию, которая будет выполнять эту работу - код будет скомпилирован только один раз (или использовать new Function).

e2-e4 08.11.2017 17:05

Чуваку, говорящему о внедрении кода, который получил 40+ голосов ... нет. Любой, кто имеет доступ к вашему сайту до того, как пользователь коснется его, может запустить код на вашем сайте и может сбросить свои собственные js-файлы, которые влияют на данные пользователя без вашего разрешения, и для этого не требуется eval. Любой, кто вводит js ПОСЛЕ того, как пользователь прикоснулся к нему, ВСЕГДА может разместить свои js на вашей странице без eval. Это похоже на то, что вы делаете с расширениями Chrome, используя сценарии содержимого, а также с браузерами без головы или простыми старыми инструментами разработчика. Дерьмо, которое ты можешь творить, бесконечно. Я все еще жду, чтобы увидеть хоть один пример клиентского js eval evil

user1816910 13.11.2018 00:13

@AaronLoften Хакеры - не боги. У них нет вашего пароля администратора. Они молча очищают ваш сайт на предмет крошечных обрывков информации и слабых мест. Они могли даже использовать социальную инженерию, чтобы заполнить пробелы. Никакая информация не оказывает серьезного воздействия, но все вместе это может стать настоящим нарушением безопасности. Инъекции (включая eval) - это вишенка на торте; это завершает атаку. Google, Facebook, а также крупные интернет-магазины и банки ежедневно сталкиваются с этим. Почему вы не читаете об этом больше? Потому что компании не любят выплескивать душу.

Ruud Helderman 15.07.2019 00:09

Интересно, почему никто не поднял это? Использование eval() ограничивает JS-движки от выполнения какой-либо оптимизации для этого блока кода, которую они обычно делают во время компиляции, поскольку код eval() может быть оценен только во время выполнения, поэтому браузерные движки будут пессимистами и просто не будут через процесс оптимизации, так как он ничего не может предсказать. Подробнее -> github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closure‌ s /…

Sasuke_214 05.11.2019 12:32

Я видел, как люди выступают за то, чтобы не использовать eval, потому что это зло, но я видел, что те же люди используют Function и setTimeout динамически, поэтому они используют eval под капотами: D

Кстати, если ваша песочница недостаточно уверена (например, если вы работаете на сайте, который разрешает внедрение кода), eval - последняя из ваших проблем. Основное правило безопасности заключается в том, что ввод все является злом, но в случае JavaScript выравнивать сам JavaScript может быть злом, потому что в JavaScript вы можете перезаписать любую функцию, и вы просто не можете быть уверены, что используете настоящую, так что, если вредоносный код запускается раньше вас, вы не можете доверять ни одной встроенной функции JavaScript: D

Теперь эпилог к ​​этому посту:

Если вам нужен В САМОМ ДЕЛЕ (80% времени требуется eval - НЕТ) и вы уверены в том, что делаете, просто используйте eval (или лучшую функцию;)), замыкания и ООП покрывают 80/90% случай, когда eval можно заменить с использованием другой логики, остальное - это динамически сгенерированный код (например, если вы пишете интерпретатор) и, как вы уже сказали, оценка JSON (здесь вы можете использовать безопасную оценку Крокфорда;))

И как указал сам Крокфорд, текущие веб-браузеры имеют встроенную функцию JSON.parse.

Ruud Helderman 14.07.2019 18:40

Если это действительно необходимо, eval - это не зло. Но в 99,9% случаев использования eval, с которыми я сталкиваюсь, требуется нет (не включая материал setTimeout).

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

eval не требуется для setTimeout. Вы также можете использовать здесь ссылку на функцию.

Matthew Crumley 20.12.2008 22:50

Я считаю, что eval - очень мощная функция для клиентских веб-приложений и безопасная ... Так же безопасна, как JavaScript, а это не так. :-) Проблемы безопасности - это, по сути, проблема на стороне сервера, потому что теперь с помощью такого инструмента, как Firebug, вы можете атаковать любое приложение JavaScript.

Использование eval должно быть защищено от XSS-атак, что не всегда легко исправить.

Benjamin 19.09.2016 12:52

Microsoft объясняет, почему eval () работает медленно в их браузере, в блоге IE, Рекомендации по производительности IE + JavaScript, часть 2: Неэффективность кода JavaScript.

eval редко бывает правильным выбором. Хотя может быть множество случаев, когда вы можете выполнить то, что вам нужно, объединив сценарий и запустив его на лету, в вашем распоряжении обычно есть гораздо более мощные и удобные в обслуживании методы: нотация ассоциативного массива (obj["prop"] - это то же самое, что и obj.prop), замыкания, объектно-ориентированные методы, функциональные методы - используйте их вместо этого.

Что касается клиентского скрипта, я думаю, что вопрос безопасности - спорный. Все, что загружается в браузер, может быть изменено и должно рассматриваться как таковое. Существует нулевой риск при использовании оператора eval (), когда есть гораздо более простые способы выполнения кода JavaScript и / или манипулирования объектами в DOM, такими как строка URL-адреса в вашем браузере.

javascript:alert("hello");

Если кто-то хочет манипулировать своим DOM, я говорю, уходите прочь. Ответственность за безопасность для предотвращения любого типа атак всегда должна лежать на серверном приложении, точка.

С прагматической точки зрения нет никакой пользы от использования eval () в ситуации, когда все можно сделать иначе. Однако есть особые случаи, когда СЛЕДУЕТ использовать eval. В таком случае это определенно можно сделать без риска взорвать страницу.

<html>
    <body>
        <textarea id = "output"></textarea><br/>
        <input type = "text" id = "input" />
        <button id = "button" onclick = "execute()">eval</button>

        <script type = "text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

Re "Нет никакого риска в использовании оператора eval (), когда есть гораздо более простые способы выполнения javascript и / или манипулирования объектами в DOM". Внедрение кода представляет собой проблему, когда один пользователь может ввести код, который затем запускается в браузере другого пользователя. Консоли браузера сами по себе не позволяют одному пользователю запускать код в браузере другого пользователя, поэтому они не имеют значения при принятии решения о том, стоит ли защищаться от внедрения кода.

Mike Samuel 04.08.2012 02:30

Разве <head></head> не требуется, даже если он пуст?

Peter Mortensen 14.01.2017 01:57

Этот ответ полностью игнорирует риски XSS.

Ruud Helderman 14.07.2019 17:56

Возьмем настоящих людей:

  1. В каждом крупном браузере теперь есть встроенная консоль, которую ваш потенциальный хакер может использовать в изобилии для вызова любой функции с любым значением - зачем им использовать выражение eval - даже если бы они могли?

  2. Если для компиляции 2000 строк JavaScript требуется 0,2 секунды, какова моя потеря производительности, если я оцениваю четыре строки JSON?

Даже объяснение Крокфорда «eval - это зло» слабо.

eval is Evil, The eval function is the most misused feature of JavaScript. Avoid it

Как мог бы сказать сам Крокфорд: «Подобные утверждения имеют тенденцию вызывать иррациональный невроз. Не покупайтесь на это».

Понимание eval и знание того, когда он может быть полезен, гораздо важнее. Например, eval - разумный инструмент для оценки ответов сервера, сгенерированных вашим программным обеспечением.

Кстати: Prototype.js вызывает eval напрямую пять раз (в том числе в evalJSON () и evalResponse ()). jQuery использует его в parseJSON (через конструктор функций).

JQuery использует встроенную в браузер функцию JSON.parse, если она доступна (что намного быстрее и безопаснее), используя eval только как резервный механизм. Утверждение «eval - это зло» является достаточно хорошим ориентиром.

jjmontes 12.09.2011 17:21

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

Mike Samuel 04.08.2012 02:29

«Каждый крупный браузер теперь имеет встроенную консоль ... зачем им использовать выражение eval?» - Вы ошибаетесь. Предлагаю вам отредактировать ответ. Возможность одного пользователя внедрить код, который может работать в другом браузере, является серьезной проблемой. И именно здесь вам нужно стать настоящим.

akkishore 27.12.2012 12:24

Кто вообще такой Крокфорд? Вы правы, злоумышленник может использовать любой инструмент HTTP-выщелачивания, чтобы имитировать браузер и делать что угодно, ему не нужен EVAL.

Akash Kava 19.04.2013 14:29

@akkishore, я буду признателен, если вы приведете пример из реальной жизни, подтверждающий ваши чрезмерно заявленные утверждения.

Akash Kava 19.04.2013 14:31

@AkashKava DNS отравляет / MITM, перехватывает и редактирует данные eval () ed и ка-бум!

akkishore 19.04.2013 19:17

@akkishore, это не имеет ничего общего с EVAL, это означает, что вы не защитили свой DNS или прокси или что-то еще, помните больше, чем браузер, у злоумышленника есть много инструментов, чтобы нанести вред, кроме EVAL, написание таких слов ничего не доказывает, покажите мне рабочий код, а это зло в EVAL, делайте это на любом безопасном DNS. Если браузер или клиентская машина скомпрометированы, EVAL еще не является злом.

Akash Kava 19.04.2013 20:08

@AkashKava Давайте упростим. Предлагаете ли вы разработать наши API / интерфейсы для приема исполняемого кода в качестве входных данных, которые выполняются без проверки работоспособности? Для тех, кто говорит, что вы можете использовать консоль для вызова любых функций, обратите внимание, что закрытие, доступное для eval'ed кода, может быть недоступно для консоли, делайте то, что вы можете!

akkishore 19.04.2013 20:25

@akkishore, какой вред он может нанести браузеру? да, если это код на стороне сервера, например php или ruby ​​на сервере или C# на сервере, тогда да, он должен быть проверен на безопасность. Допустим, все, что я наберу в этом поле для комментариев, будет оценено, какой вред это нанесет серверу переполнения стека? ничего такого. Это ваш серверный код, который должен быть безопасным, браузер в любом случае очень безопасен, поскольку он не предлагает никаких встроенных подключений в любой форме. В целом EVAL вне песочницы - зло, но внутри браузера в песочнице вреда нет.

Akash Kava 19.04.2013 20:36

@AkashKava, я думаю, что другие здесь намекнули на это, но eval действительно проблема. Атака с использованием межсайтовых сценариев (XSS) - это когда злоумышленник заставляет JS-код запускаться в контексте браузера другого пользователя. Вы думаете, что с этим делать? Они могут украсть ваш сеанс и выдать себя за вас на этом сайте. Они могут публиковать спам-комментарии. Они могут собирать вашу личную информацию. Представьте, что это произошло на веб-сайте банка: они могли украсть ваши номера счетов и остатки средств. Предлагаю вам прочитать en.wikipedia.org/wiki/Cross-site_scripting.

Brian Donovan 06.02.2014 20:04

@BrianDonovan, как это возможно сейчас? Какой браузер позволяет запускать js в контексте другого домена. Статья - история, только http Cookie скрывает сессию и куки от js. Все основные браузеры очень хорошо защищают личную информацию. Дело в том, что мало знаний опаснее. Вы можете не использовать EVAL и не применять http только к более вредоносным файлам cookie. Отказ от использования EVAL не решит никаких проблем, безопасность вашего сервера должна быть строгой, независимо от EVAL.

Akash Kava 07.02.2014 08:18

@AkashKava, Безопасность сервера важна, но это не единственная часть истории. Кроме того, мы не говорим о запуске кода в контексте другого домена, мы говорим о внедрении HTML в браузер другого пользователя в том же домене. Например, если вы управляете сайтом, который позволяет людям публиковать комментарии, используя подмножество HTML, вы должны быть очень осторожны, чтобы не разрешить такой HTML: <div onclick = "malicious code">. Это не просто. Если вы разрешите запуск этого HTML-кода в браузере другого пользователя, злоумышленник может делать плохие вещи, как я упоминал в своем последнем комментарии.

Brian Donovan 10.02.2014 21:25

@AkashKava Что вы не понимаете, так это того, что если я отправлю javascript в поле для комментариев, и этот javascript попадет в базу данных. Когда другой пользователь просматривает этот комментарий (в который я вставляю javascript), eval принимает этот javascript при его рендеринге и оценивает его с помощью интерпретатора, в результате чего мой встроенный javascript запускается в браузере другого пользователя. Делая это, я могу собирать всевозможную информацию. Их имя пользователя, их идентификатор пользователя в базе данных, их адрес электронной почты и т. д. Это не сложный ответ, если бы у вас был Googled XSS, вы бы через 10 секунд увидели, почему это проблема.

Kyle Richter 06.08.2014 02:43

Этот ответ настолько невероятно неправильный, что я шокирован, что он вообще получил какие-то положительные голоса. Eval JSON? Ты не в своем уме? Вы когда-нибудь слышали о парсерах или внедрении кода?

Francois Bourgeois 22.01.2016 13:00

@KyleRichter, вот и вы, когда JavaScript превращается в базу данных, это прекрасный пример вашей слабой безопасности на стороне сервера. Злоумышленник может легко использовать что угодно, кроме браузера, даже простой curl может отправить JavaScript в базу данных. Опасен не eval, это ваша слабая защита позволяет коду попасть в базу данных, что вызывает все проблемы, которые, кстати, злоумышленник может обойтись даже без eval.

Akash Kava 09.06.2016 09:05

@AkashKava Я не знаю, почему я даже удостоен этого ответом, но это так. Javascript в строке сам по себе не вреден, но использование eval приведет к тому, что этот javascript будет ЗАПУСКАЕТСЯ, тогда как в противном случае он будет интерпретирован как строка, которая не будет проанализирована. Я не возражаю, что на стороне сервера должно происходить экранирование, однако использование eval - это просто ПРОСЬБА, чтобы кто-то нашел способ использовать это поле. Независимо от того, как вы это утверждаете, это ДЕЙСТВИТЕЛЬНО представляет угрозу безопасности и ЯВЛЯЕТСЯ плохой практикой. Период. Вот почему все здесь повторяют то, что я сказал о НЕ использовании eval.

Kyle Richter 09.06.2016 21:22

@AkashKava Еще одна вещь. eval () полезен тогда и только тогда, когда вы можете ГАРАНТИРОВАТЬ, что ЕДИНСТВЕННЫЙ возможный ввод - это javascript, который сгенерировал ВАШЕ приложение. Но даже в этом случае это полезно только потому, что нет варианта ЛУЧШЕ. Prototype.js использовал eval, потому что это было единственное, что им было доступно для их требований, и они делали это там, где ЗНАЛИ, что целостность кода была чистой.

Kyle Richter 09.06.2016 21:28

Этот ответ игнорирует всю концепцию межсайтового скриптинга.

Jay Sullivan 03.01.2017 20:11

Когда eval () в JavaScript не является злом?

Я всегда пытаюсь отговорить от использования eval. Почти всегда доступно более чистое и удобное в обслуживании решение. Оценка не нужен даже для парсинга JSON. Оценка добавляет к аду техобслуживания. Недаром его осуждают такие мастера, как Дуглас Крокфорд.

Но я нашел один пример, в котором использовался должно быть:

Когда нужно передать выражение.

Например, у меня есть функция, которая создает для меня общий объект google.maps.ImageMapType, но мне нужно сообщить ей рецепт, как он должен создавать URL-адрес плитки из параметров zoom и coord:

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

Похоже, его можно реорганизовать, чтобы не использовать eval () - tileURLexpr - это просто шаблон, поэтому разумное использование replace () сработает. Тем не менее, это напоминает мне пример, который я имел в виду, когда отправлял вопрос, который был связан с предоставлением пользователю возможности указать математическую формулу для оценки, аналогично функциональности электронных таблиц. Конечно, тогда я не упомянул об этом, потому что не хотел влиять на ответы!

Richard Turner 11.05.2012 17:10

tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },

Casey Chu 30.10.2013 13:32

Когда вы анализируете структуру JSON с помощью функции синтаксического анализа (например, jQuery.parseJSON), она ожидает идеальной структуры файла JSON (каждое имя свойства заключено в двойные кавычки). Однако JavaScript более гибкий. Следовательно, вы можете использовать eval (), чтобы этого избежать.

Не используйте вслепую eval, особенно. при получении данных JSON из стороннего источника. См. JSON.Stringify без кавычек на свойствах? для правильного подхода к синтаксическому анализу «JSON без заключенных в кавычки имен».

Rob W 21.07.2012 00:58

Если он не использует двойные кавычки вокруг имен свойств, это может быть строковое представление литерала объекта, но это не JSON. JSON определяет имена свойств как string и определяет string как последовательность из нуля или более символов Юникода, заключенных в двойные кавычки с использованием экранирования обратной косой черты.

Useless Code 19.03.2013 17:34

См. Статью Николаса Закаса - «eval () не зло, просто неправильно понят» nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderst‌ ood

vitmalina 12.07.2013 09:16

@vitmalina Из статьи Закаса: «Это может быть опасно, если вы принимаете вводимые пользователем данные и запускаете их через eval (). Однако, если ваш ввод не от пользователя, существует ли реальная опасность?» В этом и проблема. Как только ваш код выходит за рамки «привет, мир», быстро становится невозможным доказать, что вы не пропускаете пользовательский ввод в eval. В любом серьезном мультитенантном веб-приложении, когда десятки разработчиков работают над одной и той же кодовой базой, это недопустимо.

Ruud Helderman 14.07.2019 02:14

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

Я написал фреймворк, в котором разработчики не используют EVAL, но используют наш фреймворк, и, в свою очередь, этот фреймворк должен использовать EVAL для создания шаблонов.

Производительность EVAL можно увеличить, используя следующий метод; вместо выполнения сценария вы должны вернуть функцию.

var a = eval("3 + 5");

Он должен быть организован как

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

Кеширование f, безусловно, повысит скорость.

Также Chrome позволяет очень легко отлаживать такие функции.

Что касается безопасности, использование eval или нет вряд ли будет иметь какое-либо значение,

  1. Прежде всего, браузер вызывает весь скрипт в песочнице.
  2. Любой код, который является злом в EVAL, является злом в самом браузере. Злоумышленник или кто угодно может легко внедрить узел сценария в DOM и сделать что угодно, если он / она может что-нибудь оценить. Отказ от использования EVAL не имеет никакого значения.
  3. Вредна в основном слабая безопасность на стороне сервера. Плохая проверка файлов cookie или плохая реализация ACL на сервере вызывают большинство атак.
  4. Недавняя уязвимость Java и т. д. Была в собственном коде Java. JavaScript был и предназначен для работы в песочнице, тогда как апплеты были разработаны для работы вне песочницы с сертификатами и т. д., Которые приводят к уязвимостям и многим другим вещам.
  5. Написать код для имитации браузера несложно. Все, что вам нужно сделать, это сделать HTTP-запрос к серверу с вашей любимой строкой пользовательского агента. Все инструменты тестирования в любом случае имитируют браузеры; если злоумышленник хочет причинить вам вред, EVAL - его последнее средство. У них есть много других способов борьбы с вашей серверной безопасностью.
  6. DOM браузера не имеет доступа к файлам, а не к имени пользователя. Фактически, на машине нет ничего, к чему eval может предоставить доступ.

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

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

"FirstName + ' ' + LastName"

В отличие от

"LastName + ' ' + FirstName"

Как мое отображаемое имя, которое может быть взято из базы данных и не жестко запрограммировано.

Вы можете использовать функцию вместо eval - function (first, last) { return last + ' ' + first }.

Konrad Borowski 15.10.2013 23:10

Имена столбцов взяты из базы данных.

Akash Kava 15.10.2013 23:49

Угроза eval в основном другие пользователи. Допустим, у вас есть страница настроек, на которой вы можете указать, как ваше имя будет отображаться для других. Предположим также, что вы не очень ясно думали, когда писали это, поэтому в вашем поле выбора есть такие параметры, как <option value = "LastName + ' ' + FirstName">Last First</option>. Я открываю свои инструменты разработчика, меняю value параметра на alert('PWNED!'), выбираю измененный параметр и отправляю форму. Теперь, когда кто-то другой видит мое отображаемое имя, этот код запускается.

cHao 15.01.2014 19:05

@cHao, тот, о котором вы говорите, является примером плохой безопасности на стороне сервера, сервер никогда не должен принимать данные, которые могут быть выполнены как код в любом браузере. И снова вы не смогли понять концепцию плохой безопасности на стороне сервера.

Akash Kava 09.06.2016 09:01

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

cHao 12.06.2016 07:20

«Если ваша серверная безопасность достаточно надежна, чтобы кто-нибудь мог атаковать откуда угодно, вам не стоит беспокоиться о EVAL». Именно поэтому вы беспокоитесь о должен. Ни один сервер не защищен на 100%. Утечка паролей, социальная инженерия, озлобленные сотрудники, баги безопасности. Недостаточно, чтобы обыскать систему. Но если бы я мог обновить только одну запись в вашей базе данных, я бы выбрал исходную таблицу вашего строкового процессора. Возможная XSS-атака! Так работают хакеры. У них нет пароля администратора. Они находят крошечные слабые места, ни одна из которых не имеет реального значения. Но в совокупности их может быть достаточно, чтобы нанести реальный ущерб.

Ruud Helderman 14.07.2019 21:34

Мой пример использования eval: импорт.

Как это обычно делается.

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

Но с помощью eval и небольшой вспомогательной функции он выглядит намного лучше:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable может выглядеть так (эта версия не поддерживает импорт конкретных элементов).

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

+1 за идею, но у вас тут ошибка: .replace(/name/g, name).replace('path', path). Если name содержит строку "path", вы можете получить сюрпризы.

wberry 25.03.2014 19:36

Объявление одной переменной для каждого свойства components - возможный запах кода; рефакторинг вашего кода может полностью устранить «проблему». Ваше текущее решение - просто синтаксический сахар. Если вы настаиваете на этом, я бы порекомендовал написать собственный препроцессор, который будет выполняться перед развертыванием. Это должно держать eval подальше от производственного кода.

Ruud Helderman 14.07.2019 17:40

Eval полезно для генерации кода, когда у вас нет макросов.

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

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

Ruud Helderman 14.07.2019 15:31

Если вы сгенерировали код javascript и хотели бы немедленно его выполнить (скажем, для повышения производительности по сравнению с прямой интерпретацией), это был бы вариант использования eval.

Erik Haliewicz 17.07.2019 01:28

Хорошая точка зрения; Я видел пример в эта статья о Blockly. Я шокирован, что Google рекомендует eval, когда альтернатива (Функция) и быстрее (как объяснено в MDN), и более надежна (предотвращает непредсказуемые ошибки за счет лучшей изоляции между сгенерированным кодом и другим «вспомогательным» кодом на той же веб-странице).

Ruud Helderman 17.07.2019 15:03

При отладке в Chrome (v28.0.1500.72) я обнаружил, что переменные не привязаны к замыканиям, если они не используются во вложенной функции, производящей замыкание. Думаю, это оптимизация движка JavaScript.

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

Вот мой тестовый код:

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

Я хотел бы здесь отметить, что eval () не обязательно должен ссылаться на встроенную функцию eval(). Все зависит от названия функции. Таким образом, при вызове собственного eval() с псевдонимом (скажем, var noval = eval;, а затем во внутренней функции noval(expression);) оценка expression может завершиться ошибкой, когда он ссылается на переменные, которые должны быть частью замыкания, но на самом деле это не так.

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

В основном из

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

К этому

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

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

Вы можете увидеть, как была достигнута генерация кода, если вам интересно здесь.

«Гиперскрипт сначала создается как строка (...)» Имеет смысл выполнить генерацию всего кода на этапе сборки, записать полученный гиперсрипт в отдельный исполняемый файл (.js), затем развернуть этот файл для тестирования и производство. Мне нравится, как вы используете генерацию кода. Просто eval является намеком на то, что некоторая ответственность, которая принадлежит времени компиляции, перешла во время выполнения.

Ruud Helderman 14.07.2019 17:11

На стороне сервера eval полезен при работе с внешними скриптами, такими как sql, Infxdb или mongo. Где настраиваемая проверка во время выполнения может быть выполнена без повторного развертывания ваших служб.

Например, служба достижений со следующими метаданными

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

Которые затем позволяют,

  • Прямая инъекция объекта / значений через буквальную строку в json, полезна для создания шаблонов текстов

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

Против этого:

  • Могут быть ошибки в коде и поломки в сервисе, если не полностью протестированы.

  • Если хакер может написать сценарий в вашей системе, вы в значительной степени облажались.

  • Один из способов проверить ваш скрипт - хранить хеш скриптов в безопасном месте, чтобы вы могли проверить их перед запуском.

Хороший. Когда я задал вопрос, я даже не думал о серверном JS.

Richard Turner 14.02.2018 11:48

Я думаю, что оправдание 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 - это зло, если он запущен на сервере с использованием ввода, отправленного клиентом, который был не создано разработчиком или был не продезинфицирован разработчиком.

eval - это не зло, если он запущен на клиенте, даже при использовании необработанного ввода, созданного клиентом.

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

Рассуждение

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

Eval - это не зло, им просто злоупотребляют.

Если вы создали код, входящий в него, или можете ему доверять, все в порядке. Люди продолжают говорить о том, что ввод пользователя не имеет значения для eval. Ну вроде ~

Если пользовательский ввод поступает на сервер, затем возвращается клиенту, и этот код используется в eval без очистки. Поздравляю, вы открыли ящик пандоры для отправки кому угодно пользовательских данных.

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

Просто нужно понять, какой смысл использовать eval. Генерация кода не совсем идеальна, если можно просто создавать методы для подобных вещей, использовать объекты и т.п.

А теперь хороший пример использования eval. Ваш сервер читает созданный вами файл swagger. Многие параметры URL создаются в формате {myParam}. Итак, вы хотите прочитать URL-адреса, а затем преобразовать их в строки шаблона без необходимости выполнять сложные замены, потому что у вас много конечных точек. Так что вы можете сделать что-то вроде этого. Обратите внимание, это очень простой пример.

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

Другие вопросы по теме