Что представляет собой «неправильное использование» функции Javascript Eval? [закрыто]

13

Eval - общеизвестно спорная языковая особенность. Дуглас Крокфорд категорически отвергает это. Мне интересно, какие конкретные риски приносит Эвал. По этому вопросу Improper use of eval opens up your code for injection attacks.

Какое неправильное использование команды Eval, и какие дыры в безопасности они открывают?

Дерек Адэйр
источник

Ответы:

31

Когда я реализовывал движок JScript, я выступал за то, чтобы печатать рубашки EVAL IS EVIL , но, к сожалению, мы так и не смогли обойти это.

Моя самая большая проблема с eval - не очевидная атака внедрения вредоносного кода, хотя это, безусловно, вызывает огромную обеспокоенность. Моя самая большая проблема в том, что люди склонны использовать его как действительно большой молот для решения действительно небольших проблем. Большинство реальных случаев использования eval в дикой природе, когда я был в команде JScript, можно было легко решить с помощью таблицы поиска; и так как каждый объект в JScript уже является справочной таблицей, это не так обременительно. Eval снова запускает компилятор и полностью уничтожает способность компилятора оптимизировать ваш код .

Еще несколько мыслей в этом ключе смотрите в моих статьях 2003 года на эту тему:

Общее зло:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

Инъекция атаки зла:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx

Эрик Липперт
источник
Что вы думаете о evalсоздании больших кусков кода так, как это нравится приложениям вроде JSPacker? JSPacker + gzip обычно приводит к меньшим размерам файлов, чем любое другое решение само по себе, но, как вы правильно заметили, это по сути запускает компилятор дважды для одного и того же куска кода, а также накладные расходы для замены строк.
Мэтью Шарли,
2
@ Матфея: часто есть компромисс между пространством и временем, и использование этого компромисса может иногда быть большой победой. Если целью метода является повышение производительности, то, по моему мнению, если тщательные измерения покажут, что это значительный выигрыш в реалистичных сценариях без введения дыр в безопасности, прекрасно, сделайте это. Но я не знаю достаточно о конкретной технике, чтобы критиковать ее детали.
Эрик Липперт
Я хочу один из ответов , которые я видел как здесь или на SO сам бы сказал какой ваша вторая ссылка гласит: что eval()это не создает угроза безопасности на клиент (браузер) коде.
sq33G
4

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

В качестве тривиального и бесполезного примера приведем упрощенный калькулятор JavaScript:

textbox1.value = eval(textbox2.value);

Одним из правильных примеров использования являются некоторые из упаковщиков JavaScript, которые сжимают JavaScript, вытаскивая общие слова и заменяя их короткими заменами из 1-2 символов. Затем упаковщик выводит все это вместе с кодом замены строки на основе сгенерированного словаря, а затем проверяет результат.

Мэтью Шарли
источник
1

Есть некоторые вещи, которые невозможно сделать в JS без Eval подобных функций ( eval, Function, и , возможно , больше).

Взять applyк примеру. Его легко использовать при использовании обычных вызовов функций:

foo.apply(null, [a, b, c])

Но как бы вы сделали это для объектов, которые вы создаете с помощью нового синтаксиса?

new Foo.apply(null, [a, b, c]) не работает, и не делают аналогичные формы.

Но вы можете обойти это ограничение с помощью evalили Function(я использую Functionв этом примере):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

Пример:

Foo.New.apply(null, [a, b, c]);

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

Томас Эдинг
источник
2
Верно, но вопрос ОП был: « Какое неправильное использование команды Eval и какие дыры в безопасности они открывают? », А не « Что такое хорошее применение eval()? »
Росс Паттерсон,
1
@RossPatterson: Думаю, я в основном смотрел на заголовок вопроса, ха-ха.
Томас Эдинг
Тем не менее, +1 за то, что вы нашли хорошее применение плохой языковой функции :-)
Росс Паттерсон
1

Несколько прямым ответом с моей стороны была разработка ориентированной на разработчика области тестирования API. Мы дали текстовую область на странице и кнопку Run. Центральная точка страницы была для них, чтобы они могли испытать вещи в Javascript против нашего API-интерфейса для взаимодействия с iframe, что было не так легко сделать в локальной среде.

Все злонамеренное, что могло быть сделано в этом случае, могло также быть сделано разработчиком, открывшим свои инструменты F12.

Katana314
источник
0

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

В Firefox появилась новая экспериментальная функция asm.js, с которой я работал. Это позволяет скомпилировать ограниченное подмножество языка Javascript в нативный код. Да, это очень круто, но у него есть ограничения. Вы можете думать об ограниченном подмножестве Javascript как о C-подобном языке, встроенном в Javascript. Это на самом деле не предназначено для чтения или написания людьми.

Это ограниченное подмножество Javascript не позволяет мне вставлять сгенерированный во время выполнения код в скомпилированный код после его компиляции.

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

Печенье из рисовой муки
источник
0

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

Тем не менее, мне нравится использовать evalдля двух видов вещей (хотя, возможно, могут быть и лучшие, менее злые альтернативы):

  1. Поскольку evalэто способ «явного кеширования кода», его можно использовать для повышения производительности. Обратите внимание, что оптимизаторы постоянно улучшаются, но просто нет никакой гарантии относительно того, что они могут сделать для вас. Делая вещи явными в коде, вы действительно можете помочь оптимизатору принимать более разумные решения.
  2. Он также может использоваться для предоставления базовых форм безопасности типов, а также других языковых функций, которые отсутствуют в JS, без ухудшения производительности.

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

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

Доми
источник
-3

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

У меня есть несколько таблиц: table1ResultsTable, table2ResultsTable, tableNResultsTable. У меня есть переменные с одинаковыми именами, которые являются объектами данных JQuery. Я использую их для настройки таблиц и вызова функций с данными jQuery.

Каждой таблице присвоен класс = "resultsTable". Теперь мне нужно получить переменную при нажатии на таблицу. Я делаю это:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

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

BobRodes
источник
1
Зачем тебе eval? Идентификатор должен быть простой строкой, а не кодом. Во всяком случае, event.target.parentElement.parentElement.parentElementэто ужасно. Кроме того, я ожидаю, что вызов eval вызовет ошибку «ошибка ссылки: [идентификатор] не определена», если только вы не намеренно используете оцениваемые идентификаторы (которые являются ошибочными, неправильными и могут вызвать странные вещи, если вы закончите до создания дубликатов идентификаторов).
Брайан
Возможно, я не проясняю себя. Идентификатор является простой строкой. Это идентификатор таблицы, по которой щелкнули. У меня также есть переменная объекта (устанавливается с помощью метода jQuery datatable (), ссылающейся на ту же таблицу) с тем же именем, что и идентификатор. Я пытаюсь получить эту переменную, чтобы получить доступ к ее функциям (фактически, добавить класс "row_selected" в выбранную строку), когда таблица нажата. Однако, так как я написал это, я придумал улучшение. Я просто помещаю все ссылки на объекты в массив, называю элементы так же, как и идентификатор, и вставляю в них строку идентификатора, чтобы получить ссылку на объект.
BobRodes
Брайан, если у вас есть лучший способ найти идентификатор таблицы, по которой щелкнули, я весь в ушах. Для функции datatables мне нужно обработать событие click для ячейки и добавить класс row_selected к его parentNode. Почему я не могу просто обработать событие строки и добавить класс непосредственно к нему, я не знаю, но строка не показывает выбранный, когда я это делаю.
BobRodes
1
Возможно, я не проясняю себя. Если вы вызовете eval для простой (т.е. не-JS) строки, вы выдадите исключение. Итак, ваше использование eval не имеет смысла. Если вы генерируете объектную переменную с тем же именем, что и идентификатор, ваш код будет работать ... но мне кажется, что он сломан. Я бы лучше создал переменную с помощью document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(не сказать, что это тоже здорово, но это лучше, чем eval). Как указывает Эрик Липперт, «каждый объект в JScript уже является таблицей поиска».
Брайан
Итак, вы говорите, что добавили свойство к ссылке на элемент и задали для него ссылку на объект данных? Это звучит жестче и для меня.
BobRodes