Являются ли литералы шаблонов ES6 более безопасными, чем eval?

Для меня шаблонные литералы немного напоминают eval, и часто упоминается, что idea">использование eval - плохая идея.

Меня не волнует производительность литералов шаблонов, но Я обеспокоен инъекционными атаками (и другими проблемами безопасности, о которых я, возможно, не думаю).

Изменить

Пример того, что мне кажется странным

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

После оценки: 2

Изменить 3

Я начал изучать спецификацию ECMAScript.

Хотя я не вдаюсь в подробности, создается впечатление, что литералы шаблонов указаны безопаснее, чем eval.


person Anthony Astige    schedule 15.05.2016    source источник
comment
Чтобы задать такой вопрос, вы должны сначала понять опасность использования eval. Концепция динамической опасности одинакова и в других атаках, таких как внедрение sql. Я говорю здесь, что концепция та же самая. Это вопрос того, как вы его используете.   -  person Dane    schedule 16.05.2016
comment
Что именно вас беспокоит? Литералы шаблонов гораздо более строгие, чем eval(), поскольку все, что они делают (обычно), это оценивают выражения и приводят результат к строке.   -  person Pointy    schedule 16.05.2016
comment
Я всегда избегал eval, и я только перехожу к ES6, поэтому я не уверен, с чего начать на самом деле с потенциальными опасностями/подводными камнями шаблонных литералов. Их предполагаемое использование кажется более безопасным, но существуют ли фактические ограничения на то, как литералы шаблонов оцениваются по сравнению с eval?   -  person Anthony Astige    schedule 16.05.2016
comment
Шаблонные литералы концептуально намного ближе к конкатенации строк, чем что-либо еще. Что заставляет вас рассматривать их как связанные с eval? Вы, конечно, могли бы создать строку из шаблона и eval, как я полагаю.   -  person loganfsmyth    schedule 16.05.2016
comment
eval запускает произвольные строки как код. Я не думаю, что вы можете сделать это с литералами шаблонов. Это совершенно разные вещи.   -  person Oriol    schedule 16.05.2016
comment
Почти все безопаснее, чем eval...   -  person Leonid Beschastny    schedule 16.05.2016
comment
Сравните свой пример с console.log(counter() + ', ' + ii++ + ', ' + counter()), который является точным эквивалентом. Вы по-прежнему считаете это небезопасным?   -  person Felix Kling    schedule 16.05.2016


Ответы (3)


Одно отличие от 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)}`;

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

Обратите внимание, что тот же эффект достигается с помощью:

window[name](param);

Самый злой шаблонный литерал

Как прокомментировано, вы также можете сделать этот шаблон литералом:

`eval(str)`;

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

На примере

Вы привели такой пример:

let ii = 1;
function counter() {
    return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);

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

console.log(counter() + ', ' + (ii++) + ', ' + counter());

Время компиляции

Чтобы подчеркнуть разницу между синтаксическим анализом во время компиляции и выполнения, обратите внимание, что вы не можете запускать код с литералом шаблона, который не имеет допустимого синтаксиса.

Сравните эти два скрипта:

alert('press OK');
eval('alert("hello)');

а также:

alert('press OK');
`${alert("hello)}`;

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

Точнее, eval выполняет новый скрипт с собственными фазами компиляции и запуска. Литерал шаблона анализируется/компилируется, как и любой другой код.

person trincot    schedule 15.05.2016
comment
Понравился самый злобный шаблонный литерал :) - person gevorg; 16.05.2016
comment
Конечно, самый злой литерал шаблона должен предлагать eval. - person Oriol; 16.05.2016
comment
@trincot - Спасибо за все усилия! Компиляция и время выполнения - важный момент для меня. Я отредактировал свой вопрос, копнув глубже, но я уже лучше чувствую литералы шаблонов :) - person Anthony Astige; 16.05.2016

Я думаю, что есть одно большое различие между eval и шаблонными литералами.

eval может оценивать динамические выражения, которые не видны непосредственно из кода. Это делает его опасным, потому что вы можете оценить любую строку, которая может прийти откуда угодно: клиент/третья сторона/БД...

Однако в случае с шаблонными литералами ситуация иная.

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

Например, это будет работать с eval.

function doSomething() {
  console.log('HELLO!');
}
    
// This will work.
var expression = 'doSomething()';
eval(expression);
  

Но это не будет работать с литералами шаблонов.

// This will not.
`${expression}`;

Вам нужно вставить выражение статически, чтобы оно работало

// To make it work you need to insert it statically.
`${doSomething()}`;

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

person gevorg    schedule 15.05.2016

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

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

person Azamantes    schedule 15.05.2016
comment
Внедрение SQL и литералы шаблонов: stackoverflow.com/q/44086785/3345375 - person jkdev; 16.10.2017