// Engineering Log
HTTP, HTTPS и TLS: Часть 12 — Атаки на уровне HTTP: smuggling, подмена Host, CSRF, XSS, SSRF и отравление кеша
Опубликовано 21.10.2026
// Быстрый маршрут
Эта статья относится к теме Серверы и инфраструктура.
HTTPS защищает данные по пути, но ничего не знает о том, что внутри запроса. Большая часть атак на сайты идёт по полностью зашифрованному соединению и использует особенности самого HTTP: то, как прокси и приложение по-разному разбирают один запрос, как браузер автоматически прикладывает cookie, как приложение доверяет заголовкам. В этой части разобраны основные классы таких атак — как они работают и что настроить, чтобы от них защититься. Проверять описанное можно только на своих системах или с письменного разрешения владельца.
Request smuggling: рассинхронизация прокси и приложения
Перед приложением почти всегда стоит прокси — Nginx, HAProxy, CDN. Если прокси и приложение по-разному определяют, где кончается один запрос и начинается следующий, злоумышленник может «пронести» внутри своего запроса начало чужого.
В HTTP/1.1 длину тела задают два заголовка: Content-Length и Transfer-Encoding: chunked. Стандарт требует, чтобы при наличии обоих использовался Transfer-Encoding, но реализации ошибаются:
POST / HTTP/1.1
Host: example.ru
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLEDПрокси, который смотрит на Content-Length, передаёт приложению всё тело. Приложение, которое смотрит на Transfer-Encoding, видит конец запроса на 0, а SMUGGLED считает началом следующего запроса в том же соединении. Этот «следующий» запрос склеивается с запросом другого пользователя, пришедшим по тому же соединению между прокси и приложением. Итог — чужой ответ, кража cookie, обход правил доступа на прокси.
Вариации: Transfer-Encoding: xchunked или с пробелом перед двоеточием, который одна сторона игнорирует, а другая нет; расхождения при переводе HTTP/2 в HTTP/1.1 на прокси (H2.CL, H2.TE); Upgrade: h2c, который прокси пропускает к приложению.
Защита:
- держите прокси и серверы приложений обновлёнными — эти ошибки исправляют в каждой версии;
- прокси должен отвергать неоднозначные запросы с обоими заголовками или хотя бы удалять
Content-Lengthи не передавать его дальше; проверьте, как ведёт себя ваша связка, а не только прокси; - между прокси и приложением по возможности используйте HTTP/2 — в нём длина задаётся кадрами, и неоднозначности нет;
- не пропускайте к приложению заголовки
Upgrade: h2c.
Подмена заголовка Host
Host задаёт клиент, и приложение, которое строит по нему ссылки, доверяет пользовательскому вводу. Классический пример — сброс пароля: приложение отправляет письмо со ссылкой https://{Host}/reset?token=…. Злоумышленник запрашивает сброс пароля жертвы с Host: attacker.example, жертва получает настоящее письмо со ссылкой на чужой сайт, переходит — и токен сброса уходит злоумышленнику.
Защита:
- в Nginx заведите
default_server, который отвечает на неизвестные имена кодом 444 (закрыть соединение), а приложению передавайте только запросы с известнымиserver_name; - в приложении задайте разрешённые имена (в Django —
ALLOWED_HOSTS) и стройте абсолютные ссылки из настроек, а не из заголовка; - то же относится к
X-Forwarded-Host: не принимайте его от клиентов.
server {
listen 80 default_server;
listen 443 ssl default_server;
ssl_reject_handshake on;
return 444;
}Отравление кеша и обман кеша
Отравление кеша (cache poisoning). CDN или прокси кеширует ответ по ключу — обычно схема, хост и путь. Если ответ зависит от заголовка, не входящего в ключ (например, X-Forwarded-Host попадает в адреса скриптов на странице), злоумышленник отправляет один запрос с поддельным заголовком, кеш сохраняет испорченную страницу и раздаёт её всем посетителям.
Обман кеша (cache deception). Обратная ситуация: кеш решает, что /account/profile.css — статический файл, по расширению. Приложение игнорирует «лишнее» окончание и отдаёт личную страницу пользователя. Злоумышленник присылает жертве ссылку, её личная страница попадает в общий кеш, и злоумышленник читает её оттуда.
Защита:
- на персональных страницах —
Cache-Control: privateилиno-store; CDN должен уважать заголовки приложения, а не кешировать по расширению; - если ответ зависит от заголовка, добавляйте его в
Varyили в ключ кеша; - приложение должно отвечать 404 на несуществующие пути вроде
/account/profile.css, а не отдавать страницу/account/profile.
CSRF: запрос от имени пользователя
Браузер автоматически прикладывает cookie сайта к запросам, откуда бы они ни шли. Если пользователь вошёл в bank.example.ru, а потом открыл страницу злоумышленника с формой, которая сама отправляется на https://bank.example.ru/transfer, запрос уйдёт с cookie сессии пользователя. Это межсайтовая подделка запроса (CSRF).
Защита:
SameSiteу cookie. ПриSameSite=Lax(значение по умолчанию в современных браузерах) cookie не отправляются с POST-запросами с других сайтов. Не ставьтеSameSite=Noneбез необходимости;- CSRF-токен — случайное значение в форме, которое сервер сверяет с сессией. Есть во всех популярных фреймворках;
- проверка
Originна изменяющих запросах: он должен совпадать с вашим сайтом; - не меняйте данные по GET:
SameSite=Laxпропускает переходы по ссылкам, и GET-запрос с изменением сработает.
CORS от CSRF не защищает: он запрещает странице читать ответ, но запрос с формы уходит и выполняется.
XSS и Content-Security-Policy
Межсайтовый скриптинг (XSS) — внедрение чужого JavaScript в страницу вашего сайта: через комментарий, имя пользователя, параметр поиска, выведенный без экранирования. Скрипт работает от имени сайта: читает страницу, отправляет запросы с cookie пользователя, подменяет формы.
Защита — в несколько слоёв:
- экранирование всего пользовательского ввода при выводе; шаблонизаторы делают это по умолчанию, опасны места, где экранирование отключено (
|safe,v-html,dangerouslySetInnerHTML,innerHTML); - cookie сессии с
HttpOnly— скрипт не сможет её прочитать; - Content-Security-Policy — даже если скрипт внедрён, браузер не выполнит его, если источник не разрешён:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0m'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'Встроенные скрипты разрешаются только с одноразовым значением nonce, которое сервер генерирует для каждого ответа и ставит в <script nonce="r4nd0m">. 'unsafe-inline' в script-src практически отменяет защиту от XSS. Внедряйте CSP через Content-Security-Policy-Report-Only, собирая отчёты о нарушениях, и включайте блокировку, когда отчёты перестанут приходить.
SSRF: запросы от имени сервера
Если приложение по адресу от пользователя само скачивает что-то — картинку для превью, вебхук, импорт по ссылке, — злоумышленник может указать внутренний адрес: http://127.0.0.1:8080/admin, http://10.0.0.5:9200/, адрес метаданных облака http://169.254.169.254/. Запрос уйдёт изнутри вашей сети, где нет межсетевого экрана и часто нет авторизации. Через метаданные облака можно получить временные ключи доступа к облачному аккаунту.
Защита:
- проверяйте адрес после разрешения имени: запрещайте частные, локальные и служебные диапазоны (
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,::1,fc00::/7); - проверяйте и каждый редирект: внешний адрес может перенаправить на внутренний;
- защищайтесь от смены DNS между проверкой и запросом (DNS rebinding): подключайтесь к тому IP, который проверили;
- в облаках включайте защищённый режим метаданных (в AWS — IMDSv2, требующий токен в заголовке);
- лучше всего — выделить такие запросы в отдельный сервис или прокси без доступа во внутреннюю сеть.
Внедрение CRLF и разбиение ответа
Заголовки HTTP/1.1 разделяются символами \r\n. Если приложение подставляет ввод пользователя в заголовок без проверки — например, в Location при редиректе, — злоумышленник передаёт %0d%0a и дописывает свои заголовки или даже тело ответа: установить cookie, внедрить скрипт, отравить кеш. Современные фреймворки запрещают переводы строк в заголовках, но самописный код и старые библиотеки уязвимы.
В Nginx есть своя ловушка: $uri раскодирован, и в return 302 https://$host$uri; через %0d%0a можно внедрить заголовок. Используйте $request_uri — он передаётся в исходном, закодированном виде.
Открытые редиректы
Адрес вида https://example.ru/login?next=https://attacker.example после входа перенаправляет пользователя на чужой сайт. Сам по себе это не взлом, но ссылка начинается с вашего домена и вызывает доверие в фишинговых письмах, а в OAuth такой редирект может увести токен.
Защита: разрешайте в next только относительные пути на вашем сайте или адреса из списка. Проверка «начинается с /» недостаточна: //attacker.example — это адрес другого сайта.
Кликджекинг
Злоумышленник встраивает ваш сайт в прозрачный фрейм поверх своей страницы, и пользователь, думая, что нажимает кнопку на чужой странице, нажимает «Удалить аккаунт» или «Подтвердить платёж» на вашей. Защита — запрет встраивания:
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENYСамопроверка за 10 минут
Команды ниже проверяют самые частые проблемы. Запускайте их только против своих сайтов; example.ru — ваш домен, 192.0.2.10 — IP-адрес вашего сервера.
Неизвестный Host. Запрос с чужим именем на IP вашего сервера не должен попадать в приложение:
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: evil.example' http://192.0.2.10/
# хорошо: 000 (Nginx закрыл соединение по return 444) или 4xx; плохо: 200 со страницей сайта
curl -sk -o /dev/null -w '%{http_code}\n' --resolve evil.example:443:192.0.2.10 https://evil.example/
# хорошо: 000 — рукопожатие отклонено (ssl_reject_handshake)Отражение X-Forwarded-Host. Поддельное имя не должно попадать в ссылки на странице:
curl -s -H 'X-Forwarded-Host: evil.example' https://example.ru/ | grep -c evil.example # должно быть 0Флаги cookie. У cookie сессии должны быть Secure, HttpOnly и SameSite:
curl -sI https://example.ru/login | grep -i '^set-cookie'Заголовки безопасности:
for h in strict-transport-security content-security-policy x-content-type-options \
referrer-policy x-frame-options permissions-policy; do
printf '%-28s ' $h; curl -sI https://example.ru/ | grep -qi "^$h:" && echo есть || echo НЕТ
doneОткрытый редирект. Подставьте параметры, которые ваш сайт использует для возврата после входа (next, return, redirect, url):
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' 'https://example.ru/login?next=//evil.example'
# плохо: редирект на evil.exampleВнедрение CRLF:
curl -sI 'https://example.ru/%0d%0aX-Injected:%20yes' | grep -ci '^x-injected' # должно быть 0Метод TRACE должен быть выключен:
curl -si -X TRACE https://example.ru/ | head -1 # 405 или 403Личные страницы и кеш. Откройте страницу, доступную только после входа, дважды с cookie сессии и один раз без неё:
curl -sI -b 'session=ВАША_СЕССИЯ' https://example.ru/account | grep -iE '^(cache-control|x-cache|cf-cache-status|age)'В ответе должно быть Cache-Control: private или no-store, а у CDN — промах или обход кеша (MISS, BYPASS, DYNAMIC), без заголовка Age.
SSRF. Если у сайта есть функции загрузки по ссылке (аватар по адресу, импорт, вебхуки), укажите в них адрес http://127.0.0.1:22/ и http://169.254.169.254/latest/meta-data/. Приложение должно отказаться, а не вернуть содержимое или ошибку соединения с подробностями.
Request smuggling вручную проверить сложно. Для этого есть расширение HTTP Request Smuggler для Burp Suite и утилита smuggler.py; запускайте их на тестовом стенде с той же цепочкой прокси, что и в работе.
Что проверять
- Прокси и серверы приложений обновлены; запросы с одновременными
Content-LengthиTransfer-Encodingне доходят до приложения в неоднозначном виде. - Есть
default_server, который закрывает запросы с неизвестнымHost. - Персональные страницы не кешируются CDN.
- Cookie сессии:
Secure; HttpOnly; SameSite=Lax. - Есть CSP без
'unsafe-inline'для скриптов иframe-ancestors. - Серверные запросы по пользовательским адресам не достают до внутренней сети.
- Параметры редиректов проверяются по списку.
Для автоматической проверки подходят OWASP ZAP и Burp Suite: они содержат сканеры для всех перечисленных классов атак. Запускайте их на тестовом стенде — активное сканирование создаёт записи, отправляет формы и может повредить данные.
// Похожая задача
Если у вас похожая ситуация
Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.
Тема статьи
Серверы и инфраструктура
VPS, Linux, веб-стек, миграции, хостинг, базы данных и базовая эксплуатация.
Часто с этим приходят
- Перенести сайт или сервис на новый сервер
- Настроить Linux, Nginx, базу данных и бэкапы
- Разобраться, почему всё работает нестабильно
// Следующий шаг
Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.
Открыть услуги// Reviews
Отзывы по теме
Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.
Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.
Хочу выразить огромную благодарность специалисту, который настроил мне ЧПУ на OpenCart. Настроить ЧПУ оказалось легко и просто, и я рад, что наконец нашел профессионала, который сделал всё качественно и без лишних сложностей. До этого я сменил четырёх специалистов, и каждый раз возникали проблемы с настройкой, но этот человек справился с задачей идеально.
Хочу выразить огромную благодарность специалисту, который настроил мне ЧПУ на OpenCart. Настроить ЧПУ оказалось легко и просто, и я рад, что наконец нашел профессионала, который сделал всё качественно и без лишних …
Отличная работа, обращаюсь не первый раз, находит решения к сложным задачам. Рекомендую.
Отличная работа, обращаюсь не первый раз, находит решения к сложным задачам. Рекомендую.
Отличная работа! Выполнил поставленную задачу в срок и без ошибок. Было приятно сотрудничать, рекомендую.
Отличная работа! Выполнил поставленную задачу в срок и без ошибок. Было приятно сотрудничать, рекомендую.
Отличный специалист, вник в проблему, разобрался, исправил. Рекомендую.
Отличный специалист, вник в проблему, разобрался, исправил. Рекомендую.
Нужно было решить проблему с SSL сертификатом на сервере, который был выпущен через Ngnix Proxy manager. Михаил уточнил все детали, как у меня все устроено, попросил доступы чтобы оценить реальность решения задачи, т. к. до этого не сталкивался с подобным сервисом. Быстро разобрался и решил мою проблему. Идеальное сотрудничество)
Нужно было решить проблему с SSL сертификатом на сервере, который был выпущен через Ngnix Proxy manager. Михаил уточнил все детали, как у меня все устроено, попросил доступы чтобы оценить реальность решения задачи, т. …
Диагностика Nginx Proxy Manager в docker контейнере и решение проблемы
15.03.2024 · ★ 5/5
// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related