2008-09-17 6 views
452

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

+84

Не быть eval() Саймон Виллисон - http://24ways.org/2005/dont-be-eval – 2008-09-17 19:40:35

+5

Как указано в http://moduscreate.com/javascript-performance-tips-tricks/ - (новая функция (str))() более эффективна, чем eval (str). Просто мои 2 цента :) – Grgur 2012-08-02 15:05:43

ответ

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

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

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

Редактировать: Как отмечает @Jeff Walden в комментариях, # 3 сегодня меньше, чем в 2008 году. Однако, хотя может произойти некоторое кэширование скомпилированных скриптов, это будет ограничено только сценариями, которые повторяются с помощью нет модификация. Более вероятным сценарием является то, что вы оцениваете сценарии, которые каждый раз подвергались незначительной модификации и как таковые не могли быть кэшированы. Давайте просто скажем, что НЕКОТОРЫЙ код eval'd выполняется медленнее.

+2

@JeffWalden, отличный комментарий. Я обновил свой пост, хотя понимаю, что прошло уже год с момента публикации. Xnzo72, если бы вы квалифицировали свой комментарий несколько (как сделал Джефф), тогда я мог бы согласиться с вами. Джефф указал на ключ: «eval одной и той же строки несколько раз может избежать лишних операций анализа». Как бы то ни было, вы ошибаетесь; # 3 справедливо для многих сценариев. – Prestaul 2012-02-13 17:44:21

+6

@Prestaul: поскольку предполагаемый злоумышленник может использовать любой инструмент разработчика для изменения JavaScript в клиенте, почему вы говорите, что Eval() открывает ваш код для инъекционных атак? Еще не открыта? (Я говорю о клиентском JavaScript, конечно) – 2012-10-24 01:52:35

+48

@EduardoMolteni, мы не заботимся (и действительно не можем помешать) пользователям выполнять js в своих собственных браузерах. Атаки, которые мы пытаемся избежать, - это когда пользователь предоставил значения, которые будут сохранены, а затем помещены в javascript и eval'd. Например, я могу указать свое имя пользователя: `badHackerGuy '); doMaliciousThings(); `и если вы берете мое имя пользователя, присоединяете его к некоторому сценарию и оцениваете его в браузерах других людей, тогда я могу запустить любой javascript, который я хочу на своих машинах (например, заставить их добавить +1 к моим сообщениям, отправить их данные на мой сервер и т. д.) – Prestaul 2012-10-25 18:12:30

34

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

15

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

16

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

5

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

2

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

2

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

24

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

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

  2. Производительность: до кода для выполнения неизвестно, его нельзя оптимизировать. (О яваскрипте и производительности, конечно Steve Yegge's presentation)

11

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

21

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

+24

В течение 3 лет с тех пор, как я ответил на это, мое понимание того, что происходит, имеет, скажем, углубление. На самом деле создается новый контекст выполнения. См. Http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/ – 2012-01-26 03:46:28

6

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

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

4

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

4

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

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

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

+3

Не использует eval медленнее, чем просто разбирает JSON? – 2011-04-05 00:24:17

326

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

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

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

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

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

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

... который намного легче читать а также менее опасной ошибкой.

(Но тогда, кто/действительно/знали, что они делали бы сказать:.

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

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

+77

Хм, думаю, мне повезло, когда я впервые изучил JavaScript. Я всегда использовал «document.getElementById» для доступа к DOM; по иронии судьбы, я делал это только тогда, потому что у меня не было понятия, как объекты работали в JavaScript ;-) – 2009-03-15 06:45:53

+5

согласен. Иногда eval в порядке, например. для ответов JSON от webservices – schoetbi 2011-01-03 15:17:56

+37

@schoetbi: Разве вы не используете `JSON.parse()` вместо `eval()` для JSON? – nyuszika7h 2011-01-10 21:46:02

11

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

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

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

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

4

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

7

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

5

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

Другое дело, что лучше Вы получаете больше Вы пытаетесь понять, и, наконец, Вы просто не верите, что что-то хорошо или плохо, потому что кто-то сказал это :) Это очень вдохновляющий video, который помог мне больше поразмыслить :) ХОРОШАЯ ПРАКТИКА хороша, но не используйте их бесполезно :)

2

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

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

2

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

0

Я не буду пытаться опровергнуть все сказанное до сих пор, но я буду предлагать это использование 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: Кстати, я бы не советовал (для всех соображений безопасности отметил, до сих пор), что вы основываете вы имена объектов на ввод данных пользователем. Я не могу представить, какая из веских причин вам хотелось бы сделать это. Тем не менее, я думал, что я бы сказал, что это не будет хорошей идеей :)

2

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

Но если двигатель находит eval (..) в коде, он по существу должен предположить, что вся его осведомленность о местоположении идентификатора может быть недействительной, поскольку она не может знать во время lexing точно, какой код вы можете передать 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

1

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

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

4

Если вы заметили использование Eval() в вашем коде, помните мантр «Eval() есть зло.»

Этой функция принимает произвольную строку и выполняет ее как код JavaScript. Когда код в задан заранее (не определено во время выполнения), нет причин использовать eval(). Если код динамически генерируется во время выполнения, часто существует лучший способ: достичь цели без 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); 

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

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

Еще один способ предотвратить автоматические глобальные переменные - обернуть вызов в неотложную функцию.

0

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

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

* До тех пор, пока конечные точки сервера имеют правильную валидацию & санитарно-гигиенические данные, предоставленные пользователем, не имеет значения, что получает анализ и eval'd на вашем JavaScript-стороне на стороне клиента.

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

 Смежные вопросы

  • Нет связанных вопросов^_^