Являются ли литералы шаблонов 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);