Skip to content

Latest commit

 

History

History
55 lines (35 loc) · 5.13 KB

pass-values.md

File metadata and controls

55 lines (35 loc) · 5.13 KB

Как правильно подставлять значения в JS код

Допустим, у нас есть JS скрипт, вставленный в страницу, и нам надо из серверного языка вроде PHP передать в него какое-то значение: число, строку, массив или что-то еще. Вот код, который это делает:

<script>
var userName = <?= json_encode($userName); ?>;
var userId = <?= json_encode($userId); ?>;

...

json_encode генерирует JSON-объект из переданных данных. А так как JSON - это (почти) подмножество языка Яваскрипт, то (почти) любой JSON-код является корректным Яваскрипт-выражением. Таким образом, что бы мы не передавали в качестве $userName, синтаксис JS скрипта не будет нарушен.

(почти) здесь относится к паре экзотических символов которые недопустимы в JS строках, но допустимы в JSON:

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

the Unicode line separator (U+2028) and paragraph separator (U+2029) characters are permitted;

Если эти символы встретятся в $userName, и без изменений попадут в Яваскрипт-код, произойдет ошибка синтаксиса. К счастью, json_encode() кодирует эти символы как \u2028, а не вставляет, как есть, и ошибки не происходит.

Также, теоретически, в $userName может встретиться последовательность </ (или </script>), которая закрывает тег <script> и таким образом позволяет вставить произвольный HTML-код. К счастью, json_encode() экранирует слеш / как \/ и </script> превращается в <\/script>, что предотвращает эту уязвимость.

Мы намеренно не используем здесь htmlspecialchars(), который надо использовать при подстановке переменных в HTML-код. Дело в том, что в HTML-тегах script и style содержимое воспринимается как есть и HTML-мнемоники вроде &quot; не воспринимаются как кавычка. Если бы мы написали htmlspecialchars(json_encode($x)), то могли бы получить некорректный JS код вроде

var userName = &quot;Ivan&quot;;

Если не использовать json_encode(), то получается риск допустить ошибку или оставить уязвимость. Например, JS строки не могут содержать перенос строки и мы должны бы были за этим следить. Также, в JS строке не должна встречаться последовательность символов </script> или </. json_encode() решает эти проблемы.

В случае использования шаблонизатора twig с автоэкранированием надо добавить фильтр raw, чтобы он не пытался применить функцию htmlspecialchars():

<script>
var userName = {{ userName | json_encode | raw }};

Стоит вынести все переменные с подстановками в самое начало JS скрипта, а не раскидывать их по коду.

Что будет, если использовать неправильный код для подстановки значений

Неправильный код создает такие возможности атаки:

  • можно нарушить синтаксис JS и тем самым предотвратить выполнение JS скрипта
  • если удастся подставить значение </script> в строку, можно закрыть тег <script> и вставить за ним произвольный HTML код.

Вот пример неправильного кода:

<script>
var userName = '<?= $userName ?>';

Если злоумышленнику удастся подставить в $userName последовательность '; alert("hello!");var t = ' то получится инъекция и злоумышленник сможет выполнить на странице произвольный JS-код (например, ворующий куки у пользователей или делающий что-то на сайте от их имени).