Как работает htmlspecialchars()?

Всегда при выводе текста на страницу хтмл, использовал функцию htmlspecialchars($var), без дополнительных аргументов. Только сейчас узнал, что если не указывать второй аргумент, то он по умолчанию стоит ENT_COMPAT. То-есть он преобразует двойные кавычки, а одинарные кавычки не изменяются. А я то всегда думал что и одинарные тоже преобразует...
Вопрос, неужели для XSS не важно, будут ли экронироваться одинарные кавычки или нет? А то я заметил, что никто из моих знакомых не дописывает второй аргумент, а значит, одинарные кавычки не экронируются...
  • Вопрос задан
  • 841 просмотр
Пригласить эксперта
Ответы на вопрос 1
ipatiev
@ipatiev Куратор тега PHP
Потомок старинного рода Ипатьевых-Колотитьевых
Ну уж для такой-то простой функции должно быть достаточно написанного на странице документации.
И, в частности, про ENT_QUOTES ;)

Эта функция заменяет спецсимволы, которые являются управляющими в контексте HTML, на безобидные HTML-сущности. Вот и всё.
Чисто визуально управляющие символы будут выглядеть так же, как и должны, но в коде не будут представлять ни малейшей опасности.

Для XSS важно, будут ли экранироваться одинарные кавычки или нет, если одинарные кавычки используются для ограничения атрибута.
Пример

<?php $name = "' onclick='alert(\"pwned!\")"; ?>
<input value="<?=htmlspecialchars($name) ?>"> Не важно. Весь текст так и заключен в двойные кавычки
<input value='<?=htmlspecialchars($name) ?>'> Важно. Закрыли одинарную, вписываем, что хотим

Во втором случае этот код отрендерится, как
<input value='' onclick='alert(&quot;pwned!&quot;)'>
(но при этом &quot; отрендерятся в двойные кавычки, и в onclick будет уже валидный яваскрипт
alert("pwned!")

А с взведенным флагом ENT_QUOTES мы получим
<input value='&#039; onclick=&#039;alert(&quot;pwned!&quot;)'>

И хотя значение внутри атрибута отрендерится, как ' onclick='alert("pwned!"), но оно все целиком будет внутри атрибута value.

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

К счастью, РНР уже позаботился о вас и ваших друзьях. Начиная с версии 8.1, флаг ENT_QUOTES ставится по умолчанию. И приведенный выше пример будет работать только на устаревших версиях. Так что ручное добавление уже уходит в область легаси-практик.

Чтобы не ломать пальцы, каждый раз набирая всё это htmlspecialchars ENT_QUOTES, толковые джуны всегда пишут пользовательскую функцию-макрос, типа
function esc($var) {
    return htmlspecialchars($var, ENT_QUOTES);
}

Правда, надолго с этой функцией не задерживаются, потому что она годится только при обучении. А любой проект сложнее, чем домашняя страничка про любимого котика, в обязательном порядке уже должен для вывода использовать специальный шаблонизатор, например Twig. Где весь вывод идет с помощью специального оператора, который уже по умолчанию экранирует HTML
<input value="{{$name}}"> Не важно. Все уже проэкранировано до нас

Важно помнить, что это экранирование работает только в контексте HTML.
Если выводим данные внутри кода яваскрипт, то htmlspecialchars поможет как мертвому припарки. И в этом случае надо использовать json_encode.

Ну и разумеется, надо не забывать комбинировать все варианты экранирования.
Например, код яваскрипт, который пишется в атрибут HTML тега, надо весь целиком экранировать c с помощью htmlspecialchars. А данные для этого кода - c с помощью json_encode:
<button onclick="<?= htmlspecialchars("window.open(".json_encode($name).")", ENT_QUOTES) ?>">
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы