Що являє собою "неналежне використання" функції javas Eval? [зачинено]


13

Евал - горезвісно суперечлива мовна особливість. Дуглас Крокфорд відверто відхиляє це. Мені цікаво, які конкретні ризики приносить Евал. Відповідно до цього питання Improper use of eval opens up your code for injection attacks.

У чому полягає неправильне використання команди Eval і які отвори в безпеці вони відкриваються?

Відповіді:


31

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

Моя найбільша проблема з 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
@Matthew: Часто відбувається компроміс між простором і часом, і скористатися цим компромісом іноді може бути великим виграшем. Якщо метою методики є підвищення продуктивності, то, на мою думку, якщо ретельне вимірювання показує, що це реальна виграш у реалістичних сценаріях без введення отворів у безпеці, чудово, зробіть це. Але я не знаю достатньо конкретної техніки, щоб критикувати її деталі.
Ерік Ліпперт

Я хотів би, щоб одна з відповідей, яку я бачила або тут, або в самому 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()? "
Росс Паттерсон

1
@RossPatterson: Гадаю, я в основному дивився на назву питання ха-ха.
Томас Едінг

І все-таки +1 для пошуку корисної користі для функції поганої мови :-)
Росс Паттерсон

1

Дещо прямою відповіддю з мого боку була розробка області тестування, орієнтованої на розробників. Ми надали текстову область на сторінці та кнопку Запустити. Центральна точка сторінки полягала в тому, щоб вони могли випробувати речі в Javascript проти нашого програмного забезпечення, що передає iframe, що було не так просто зробити в локальному середовищі.

Будь-яке зловмисне, що могло бути зроблено в цьому випадку, також могло зробити розробник, відкривши свої інструменти F12.


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. Я використовую їх для налаштування таблиць і виклику функцій даних qQuery на них.

Кожній таблиці присвоєно class = "resultsTable". Тепер мені потрібно отримати змінну при натисканні на таблицю. Я роблю це:

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

Отож я отримую ідентифікатор таблиці, в яку натискали клітинку, яка має те саме ім'я, що і відповідна їй змінна об'єкта даних, що відповідає. Якщо хтось пропонує пропозицію щодо покращення, я хотів би дізнатися про це.


1
Для чого вам потрібен eval? Ідентифікатор повинен бути звичайним рядком, а не кодом. У всякому разі, event.target.parentElement.parentElement.parentElementце жахливо. Крім того, я очікую, що виклик eval генерує помилку "посилання помилки: [id] не визначено" помилку, якщо ви навмисно не використовуєте оцінювані ідентифікатори (що зламано, неправильно і може спричинити дивні речі, якщо ви закінчите генерування дублікатів ідентифікаторів).
Брайан

Можливо, я не даю про себе зрозуміти. ІД - це звичайна рядок. Це ідентифікатор таблиці, який натиснули. У мене також є об'єктна змінна (встановлена ​​методом jQuery datatable (), посилаючись на ту саму таблицю) з тим же ім'ям, що і id. Я намагаюся отримати цю змінну, отримати доступ до її функцій (насправді, щоб додати клас "row_selected" до вибраного рядка), коли клацнути таблицю. Оскільки я написав це, я придумав поліпшення. Я просто поміщую всі посилання на об'єкт у масив, називаю елементи так само, як і id, і підключаю рядок id до цього, щоб отримати об'єкт ref.
BobRodes

Брайан, якщо у вас є кращий спосіб знайти ідентифікатор таблиці, на яку було натиснуто, я все вухо. Для функції даних таблиць мені потрібно обробити подію клацання проти комірки та додати клас row_selected до її батьківського вузла. Чому я не можу просто обробити подію рядка і додати клас безпосередньо до неї, я не знаю, але рядок не відображається як вибраний, коли я це роблю.
BobRodes

1
Можливо, я не даю про себе зрозуміти. Якщо ви зателефонуєте eval у звичайній (тобто не-JS) рядку, ви кинете виняток. Отже, ваше використання eval не має сенсу. Якщо у вас трапляється генерація змінної об'єкта з тим же ім'ям, що ідентифікатор, ваш код буде працювати ... але вражає мене, як зламаний. Я вважаю за краще створити змінну, використовуючи document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(не кажучи, що це теж чудово, але це краще, ніж eval). Як зазначає Ерік Ліпперт, "кожен об'єкт у JScript вже є таблицею пошуку".
Брайан

Гаразд, значить, ви говорите, щоб додати властивість до посилання на елемент та встановити його на посилання на об'єкт даних, що може використовуватися? Це звучить і для мене жорсткіше.
BobRodes
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.