Pull to refresh

Comments 12

Растет уровень угроз — совершенствуется защита. Совершенствуется защита — совершенствуется малварь. Если исходить из этого, получится замкнутый круг! Сам малварь (его разработка и использование) — всего лишь следствие. Работать необходимо в первую очередь с причиной. Снижение экономической выгоды от использования малваря пропорционально снижению использования малваря. И наоборот.
Фильтрация, комплексные средства… Всю статью можно свести к одной фразе:
Используйте преобразование сущностей

При выводе значения в HTML-разметку нужно использовать преобразование сущностей.

При выводе значения внутри тега script нужно использовать JSON-кодирование. Кавычки для строк вручную писать не надо.

При этом, если вывод в HTML в атрибут типа href, то перед этим надо дополнительно сделать URL-кодирование для составных частей URL, если в атрибут типа onclick, то JSON-кодирование.

Если у вас такой редкий случай, что пользователь может вводить абсолютный URL полностью, то надо проверять, чтобы он не начинался с javascript:, а лучше разрешать только начинающийся с http:/https:.

Если у вас такой редкий случай, что вы выводите пользовательское значение внутри тега style, то нужно использовать приведение к int для числовых значений либо добавление слешей к кавычкам для строковых. При этом обрамляющие кавычки лучше добавлять в функции добавления слешей, так же как делает json_encode(), а не хардкодить в css-разметке. Потому что иначе можно ошибиться и где-нибудь случайно написать кавычки другого типа.

Для вывода пользовательского HTML нужно использовать специальные средства типа HTMLPurifier.

Надо понимать, что происходит не просто вывод значения, а вывод значения в определенный контекст.
И пусть пользователь вводит всё что хочет, не надо его ограничивать.
Если у вас такой редкий случай, что пользователь может вводить абсолютный URL полностью, то надо проверять, чтобы он не начинался с javascript:, а лучше разрешать только начинающийся с http:/https:.


так можно пропустить:
http://domain.com" onclick="javascript:...."
Оно конечно да, но кодирование сущностей тоже должно быть, тогда кавычки в URL не сломают разметку.
При выводе значения внутри тега script нужно использовать JSON-кодирование. Кавычки для строк вручную писать не надо.

Можно про этот случай подробнее? Как раз сегодня мучился с задачей как передать объект внутрь script (на стороне фронтенда) при рендеринге темплейта на стороне сервера (express + nunjucks templates). Объект содержит пользовательские данные, то есть может содержать все что угодно. Объект сериализирую в JSON чтобы потом подставить в скрипт и распарсить с помощью JSON.parse. Если выводить напрямую, то включается html экранирование nunjucks и результирующий js получается невалидный. Если отключить экранирование и выводить как есть, то в это чревато вышеописанным XSS. Что-то не получилось нагуглить внятного примера под nodejs, хотя знаю что задача актуальная и существуют методы на других шаблонизаторах (var a = {!JSENCODE(var)} к примеру в Visualforce). Нашел выход один, но так сказать через другое место — выводить JSON как обычный экранированный текст в html тег и потом вытягивать его с помощью innerHTML, а дальше парсить. Но может есть способ элегантнее?
Если пользовательские данные это например строка из БД, то можно сделать так:
<script>
    var obj = <?= json_encode($data) ?>;  // var obj = {field: "user_value", ...};
</script>


Пример на PHP, но принцип думаю везде одинаковый. То есть, на клиенте не надо делать JSON.parse, просто сразу объявляем объект, который бразуер распарсит при загрузке страницы.
А что произойдет если в json будет такая штука?
{field: "</script><script>alert('hacked')", ...};

Я без особых знаний данной темы понимаю что ничего хорошего. А если еще применять различные техники скрытия спецсимволов? По вашему примеру получается что $data без экранирования становится частью html разметки.
В PHP json_encode() экранирует слеши. У меня получается такой вывод:

<?php
    $data = ['field' => "</script><script>alert('hacked')"];
?>
<script>
    var obj = <?= json_encode($data) ?>;
</script>


<script>
    var obj = {"field":"<\/script><script>alert('hacked')"};
</script>


Никаких алертов не происходит.
Тогда вопрос сужается.
в NodeJS JSON.stringify не экранирует.
Как это реализовать в NodeJS?
Шаблонизатор (Nunjucks) который я использую не позволяет это сделать из коробки.
Пилить свою функцию которая тупо заменяет какой-то набор спецсимволов не вариант, потому что я не знаю всех возможных вариантов представления исполняемого кода чтобы быть уверенным в том что моя функция 100% рабочаю. Есть ли какое-нибудь готовое решение под NodeJS которое сделает строку безопасной для JS и при этом без всяких html entities которые выплевывает шаблонизатор.
В Nunjucks же вроде можно свой фильтр сделать? Делаете свой фильтр, который выполняет JSON.stringify(data).replace('/', '\\/'). Тут проблема только в слешах, и то только потому что браузер так закрывающий тег script внутри строки обрабатывает.
использование «белых списков» на строне сервера (проверка длины, формата, логики и.д.);
Ну, валидацию входных данных нужно делать всегда безотносительно XSS.

В отношении CSP report-uri, кто-нибудь боролся с браузерными плагинами, выполняющимися в контексте текущей страницы и вызывающими ложное срабатывание оповещения? Я так и не смог придумать универсальный способ блокировки хотя бы на стороне сервера.

Сайд-замечание: ваши «клиент-сайд» и «пейлоад» вызывают когнитивный диссонанс между зрением и внутренней речью :)
Sign up to leave a comment.