Являются ли литералы шаблонов ES6 более безопасными, чем eval?
Литералы шаблонов немного пахнут мне, как eval, и часто цитировали, что использование eval - плохая идея.
Я не заинтересован в производительности шаблонных литералов, но меня беспокоят атаки на инъекции (и другие проблемы безопасности, о которых я, возможно, и не думаю).
Edit
Пример чего-то странного для меня
let ii = 1;
function counter() {
return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
Какие выходы
1, 2, 3
Литературный шаблон создает побочные эффекты на глобальном уровне. И функцией, и непосредственно.
Изменить 2
Пример, показывающий безопасность шаблонных литералов
let ii = 1;
let inc = function() { ii++; }
console.log('Starting: ' + ii);
let input = prompt('Input something evil (suggestion: inc() or ii++)');
console.log(`You input: ${input}`);
console.log('After template literal: ' + ii);
eval(input);
console.log('After eval: ' + ii);
Если вы введете ii++
при появлении запроса, он зарегистрирует
Запуск: 1
Вы вводите: ii + = 1
После шаблона литерала: 1
После eval: 2
Изменить 3
Я начал изучать спецификацию ECMAScript
Хотя я не разбираюсь в деталях, кажется, что шаблонные литералы указаны безопаснее, чем eval.
Ответы
Ответ 1
Одно отличие от eval
заключается в том, что литералы шаблона анализируются во время компиляции, тогда как аргумент eval
обрабатывается только во время выполнения, когда выполняется eval
.
В связи с этим, eval
может получить динамически построенный аргумент, в то время как литерал-шаблон является... литералом: он не может быть сохранен как переменная шаблона, которую вы могли бы динамически строить, перемещаться и, в конечном счете, анализировать: нет типа данных "шаблонная переменная". Функция тега фактически не получает переменную шаблона в качестве аргумента, а анализируемые ее компоненты, которые известны во время компиляции.
Некоторые примеры
С eval
вы можете иметь следующую ситуацию:
var code = prompt('enter some evil code');
eval(code);
Но это невозможно в шаблонных литералах:
var literal = prompt('enter some evil template literal');
tag literal; // there is no data type or syntax for this.
`${literal}`; // and this just gives you the entered string.
Что возможно, это:
var str = prompt('enter some string');
tag`${str}`;
Но это не приводит к нежелательному исполнению кода, по крайней мере, не хуже этого:
var str = prompt('enter some string');
myfunc(str);
Любые вызовы функций должны быть закодированы буквально в литерале шаблона. Значения строковых переменных не могут изменить это. Нет никакого способа, чтобы переменная-функция вызывалась литералом шаблона. Это:
`${func(str)}`;
... вызовет func
и только эту функцию. Он выбирается программистом.
Довольно злой шаблон литерала
Сказав это, это все еще возможно:
var func = prompt ("enter some evil function name (suggestion: 'alert')");
var param = prompt ("now provide an argument for " + func);
`${window[func](param)}`;
Ответ 2
Литералы шаблонов автоматически исключают кавычки, если это вас беспокоит. Они также не выполняют ничего и не выполняют ничего, они преобразуют все, что вы вставляете в строку. Если вы беспокоитесь о SQL Injection, попробуйте сделать это с помощью шаблонных литералов, и вы увидите, что они ускользнули.
Вам следует избегать использования eval, если у вас есть действительно хорошая причина, чтобы использовать его, и вы действительно знаете, что вам нужно, чтобы достичь своей цели. В противном случае лучше избегать.
Ответ 3
Я думаю, что существует одна большая разница между eval и литералами шаблона.
eval может оценивать динамические выражения, которые непосредственно не видны из кода. Это делает его опасным, поскольку вы можете оценить любую строку, которая может появиться
из любого места: клиент/сторонний/db...
Однако в случае шаблонных литералов ситуация отличается,
- потому что вы можете видеть полный шаблон из кода,
- выражения работают с вашими внутренними объектами и не могут оценивать динамическое выражение.
Например, это будет работать с eval
function doSomething() {
console.log('HELLO!');
}
// This will work.
var expression = 'doSomething()';
eval(expression);