Почему использование функции JavaScript eval является плохой идеей?

функция eval-это мощный и простой способ динамически генерировать код, так в чем же предостережения?

25 ответов


  1. неправильное использование оценку открывает свой код для атак

  2. отладка может быть более сложным (нет номеров строк и т. д.)

  3. код eval'D выполняется медленнее (нет возможности компилировать/кэшировать код eval'D)

Edit: как указывает @Jeff Walden в комментариях, #3 сегодня менее верен, чем в 2008 году. Однако при этом может произойти некоторое кэширование скомпилированных скриптов это будет ограничено только сценариями, которые повторяются без изменений. Более вероятный сценарий заключается в том, что вы скрипты ивала подработок, которые претерпели небольшие изменения каждый раз и, как таковые, не могут быть кэшированы. Скажем так, что некоторый код eval'D выполняется медленнее.


эвал не всегда злой. Бывают моменты, когда это совершенно уместно.

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

чтобы дать слишком типичный пример, чтобы установить цвет элемента с идентификатором, хранящимся в переменной "картофель":

eval('document.' + potato + '.style.color = "red"');

если бы авторы вышеприведенного кода имели представление об основах работы объектов JavaScript, они бы поняли, что квадратные скобки могут использоваться вместо буквальных точечных имен, устраняя необходимость eval:

document[potato].style.color = 'red';

...что значительно легче читать, а также потенциально менее глючный.

(но тогда кто-то, кто/ действительно / знал, что они делают, скажет:

document.getElementById(potato).style.color = 'red';

что более надежно, чем изворотливый старый трюк доступа к элементам DOM прямо из объекта документа.)


Я считаю, что это потому, что он может выполнять любую функцию JavaScript из строки. С его помощью людям проще вводить в приложение посторонний код.


на ум приходят два момента:

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

  2. производительность: пока код не будет неизвестен, его нельзя оптимизировать. (о javascript и производительности, конечно Стив Yegge это!--10-->)


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


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


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


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

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

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

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


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


наряду с остальными ответами, я не думаю, что операторы eval могут иметь расширенную минимизацию.


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

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


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


Я знаю, что эта дискуссия старая, но мне очень нравится этой подход Google и хотел поделиться этим чувством с другими ;)

другое дело, что чем лучше вы получаете, тем больше вы пытаетесь понять, и, наконец, вы просто не верите, что что-то хорошо или плохо только потому, что кто-то так сказал :) Это очень вдохновляет видео это помогло мне больше думать самостоятельно:) хорошие практики хороши, но не используйте их бездумно:)


Это значительно снижает ваш уровень уверенности в безопасности.


Если вы хотите, чтобы пользователь вводил некоторые логические функции и оценивал, а затем функция JavaScript eval идеальна. Я могу принять две строки и eval(uate) string1 === string2, etc.


это не обязательно так плохо, если вы знаете, в каком контексте вы его используете.

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

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


если вы заметили использование eval() в своем коде, помните мантру "eval () - это зло."

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

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

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

также важно помнить, что передача строк в setInterval(), setTimeout(), и Function() конструктор, по большей части, похож на использование eval() и поэтому следует избегать.

за кулисами JavaScript все еще должен оценивать и выполнять строка, которую вы передаете как программный код:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

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

существует небольшой потенциал преимущество, поскольку код, вычисленный в new Function (), будет выполняться в локальной функции область, поэтому любые переменные, определенные с помощью var в оцениваемом коде, не станут глобалы автоматически.

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


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


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


Это одна из хороших статей, говорящих об eval и о том, что это не зло: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

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


eval () очень мощный и может использоваться для выполнения оператора JS или оценки выражения. Но вопрос не в использовании eval (), но давайте просто скажем, как строка, которую вы используете с eval (), зависит от вредоносной стороны. В конце вы будете запускать вредоносный код. С властью приходит большая ответственность. Так что используйте его мудро вы используете его. Это не связано с функцией eval (), но эта статья имеет довольно хорошую информацию: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Если вы ищете основы eval (), посмотрите здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval


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

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

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

Это все объясняет.

ссылка :

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance


Это не всегда плохая идея. Возьмем, к примеру, генерацию кода. Недавно я написал библиотеку под названием Hyperbars, который устраняет разрыв между виртуальный-дом и руль. Он делает это путем разбора шаблона руля и преобразования его в hyperscript который впоследствии используется virtual-dom. Hyperscript генерируется в виде строки сначала и перед ее возвратом, 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() не является проблемой в подобной ситуации, потому что вам нужно только интерпретировать сгенерированную строку один раз, а затем повторно использовать исполняемый вывод много раз.

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


Я бы даже сказал, что это не имеет значения, если вы используете eval() в javascript, который запускается в браузерах.*(предостережение)

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

*до тех пор, пока конечные точки вашего сервера имеют правильную проверку и очистку пользователя предоставленные значения не должны иметь значения, что анализируется и оценивается в javascript на стороне клиента.

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


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

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

EDIT: кстати, я бы не предложил (по всем причинам безопасности, указанным выше), чтобы вы основывали имена объектов на вводе пользователя. Хотя я не представляю, почему ты хочешь это сделать. Тем не менее, я подумал, что это не будет хорошей идеей :)