XSS
XSS (Cross-Site Scripting) — уязвимость, которая позволяет выполнить вредоносный JavaScript-код на странице сайта. Если система не проверяет входные данные, код может получить доступ к пользовательским данным или изменить содержимое страницы.
Любые данные, полученные от пользователей через формы или другие источники, могут содержать опасный код. Чтобы предотвратить XSS, необходимо экранировать все внешние данные перед выводом в HTML или JavaScript.
Экранировать HTML
Чтобы заменить спецсимволы на HTML-сущности используйте:
-
htmlspecialcharsbx— функция преобразует спецсимволы<,>,",',&в HTML-сущности, -
\Bitrix\Main\Text\HtmlFilter::encode— работает аналогично, но поддерживает Unicode.
Избегайте htmlspecialcharsEx — функция работает по черному списку, то есть запрещает только определенные символы. Лучше использовать полное экранирование htmlspecialcharsbx или белый список CBXSanitizer.
<!— Правильно: спецсимволы экранированы, скрипты не выполнятся —>
<div><?= \Bitrix\Main\Text\HtmlFilter::encode($foo) ?></div>
<textarea><?= \Bitrix\Main\Text\HtmlFilter::encode($foo) ?></textarea>
<!— Неправильно: если $foo содержит <script>, он выполнится —>
<div><?= $foo ?></div>
<textarea><?= $foo ?></textarea>
Экранирование можно пропускать только для доверенных данных, например, для строк из исходного кода.
Для экранирования HTML внутри Javascript, можно использовать методы класса Text встроенной библиотеки main.core.
const valueNotSafe = '<script>alert(1)</script>';
const valueEscaped = BX.Text.encode(valueNotSave); // <script>alert(1)</script>
const yetValueNotSafe = BX.Text.decode(valueEscaped); // <script>alert(1)</script>
Получить класс Text можно через импорт из библиотеки main.core.
import { Text } from 'main.core';
const valueEscaped = Text.encode(valueNotSafe);
Атрибуты
Заключайте значения атрибутов в двойные кавычки ". С одинарными кавычками экранирование не сработает.
<!— Правильно: значения в двойных кавычках —>
<input type="text" name="foo" value="<?= htmlspecialcharsbx($fooValue) ?>" />
<!— Неправильно: в одинарных кавычках экранирование может не сработать —>
<input type="text" name="foo" value='<?= htmlspecialcharsbx($fooValue) ?>' />
Экранировать JavaScript
Метод CUtil::JSEscape экранирует спецсимволы JavaScript ', ", \, \n, \r. Подходит для строк, заключенных в кавычки.
// Правильно: строка в кавычках, спецсимволы экранированы
<script>
var foo = '<?= CUtil::JSEscape($foo) ?>';
</script>
// Неправильно: без кавычек код выполнится как есть
<script>
var foo = <?= CUtil::JSEscape($foo) ?>;
</script>
Двойное экранирование
Используйте совместно экранирование HTML и JavaScript:
-
в обработчиках событий
onclick,onloadи так далее, -
атрибутах, содержащих JavaScript, например,
href="javascript:...", -
шаблонах динамических скриптов.
<?php
// Сначала экранируем для JS, затем для HTML
$someData = CUtil::JSEscape($foo);
$someData = htmlspecialcharsbx($someData);
?>
<a href="#" onclick="doSome('<?= $someData ?>');">Click</a>
Вывести JSON
Неэкранированный JSON может содержать закрывающие теги </script>, уязвимости XSS и вредоносный JavaScript.
Метод Json::encode:
-
преобразует данные в JSON,
-
экранирует спецсимволы,
-
добавляет Unicode-экранирование.
<?php
// Массив с пользовательскими данными
$foo = ['key' => $userInput];
?>
<script>
// Безопасный вывод: <script> и другие спецсимволы экранированы
var foo = <?= Bitrix\Main\Web\Json::encode($foo) ?>;
</script>
Очистить HTML теги
Если необходимо вывести HTML-код пользователя, используйте санитайзер CBXSanitizer. Он удалит опасные теги и оставит только разрешенные.
Метод sanitizeHtml преобразует полученный HTML-текст.
<div><?= (new CBXSanitizer)->sanitizeHtml($foo) ?></div>
Подробнее в статье