HTTP-заголовки — это не просто служебные строки в начале запроса или ответа. Они управляют тем, как браузер или клиентское приложение будет обрабатывать полученные данные. По стандарту имена заголовков не чувствительны к регистру, и это создаёт неожиданную зону риска. Два одинаковых заголовка, но с разным регистром — например, Content-Length
и content-length
— могут быть обработаны по-разному разными компонентами цепочки доставки данных. Именно на этой особенности и строится техника внедрения заголовков — HTTP Header Injection через дублирование в разных регистрах.
Почему регистр не имеет значения по стандарту, но важен на практике
Согласно RFC 9110 , имена заголовков HTTP регистронезависимы. Это означает, что сервер должен одинаково воспринимать Host
и host
. Однако спецификация не диктует, как именно сервер, прокси или приложение должны действовать, если таких заголовков два — пусть даже с разным регистром.
В реальных архитектурах ситуация выглядит так:
- Один компонент может объединить значения через запятую.
- Другой может оставить только первый встреченный заголовок.
- Третий — перезаписать значение последним.
- Четвёртый — воспринимать их как разные заголовки и обработать оба.
Несогласованность приводит к тому, что злоумышленник получает возможность вставить свои данные в неожиданный момент.
Механика атаки
Суть приёма в том, чтобы отправить запрос, содержащий одинаковые заголовки с разным регистром букв в имени. Это может сбить с толку одну из систем в цепочке обработки.
- Клиент отправляет запрос с двумя заголовками:
Content-Length: 100 content-length: 5
- Один из промежуточных узлов (CDN, балансировщик) считает, что заголовок один, и использует значение 100.
- Следующий узел (веб-сервер) ориентируется на последний вариант и использует значение 5.
- В результате часть данных может быть принята за новые заголовки или новый запрос, открывая путь для внедрения произвольных заголовков.
Такой подход может применяться для:
- вставки дополнительных заголовков (
Set-Cookie
,Location
,X-Forwarded-For
); - подмены кэшируемых ответов;
- создания условий для других атак (например, Request Smuggling).
Поведение популярных технологий
Разные веб-серверы и платформы обрабатывают дубликаты заголовков по-разному:
- NGINX — по умолчанию объединяет одинаковые заголовки в массив значений, но модульная логика обработки может ориентироваться на первый или последний элемент.
- Apache HTTP Server — в зависимости от модуля может перезаписать значение или объединить значения через запятую.
- Node.js (Express, Fastify) — стандартный API возвращает последний заголовок, но middleware могут работать только с первым.
- Java (Spring, Jakarta EE) — часто преобразует заголовки в карту с нормализацией регистра, но порядок обработки зависит от контейнера (Tomcat, Jetty и др.).
- Python (Flask, Django) — обычно принимает последнее значение, но при использовании сторонних WSGI-серверов возможны отличия.
Взаимосвязь с другими уязвимостями
Дублирование заголовков с разным регистром может быть элементом более сложных атак:
- HTTP Response Splitting — внедрение CRLF-последовательностей для добавления своих заголовков или тела ответа.
- HTTP Request Smuggling — несогласованная обработка длины или границ запроса разными узлами в цепочке.
- Bypass Access Control — изменение логики авторизации, если заголовки вроде
X-Forwarded-For
используются для определения клиента.
Инструменты для проверки
Для тестирования уязвимости подойдут:
- Burp Suite — гибкая модификация запросов, включая изменение регистра заголовков.
- cURL — удобен для ручной отправки запросов:
curl -v -H "Set-Cookie: a=1" -H "set-cookie: b=2" https://example.com
- Nuclei — шаблонный сканер, где легко описать проверку на дубликаты.
Как защититься
Рекомендации по защите сводятся к нормализации и фильтрации:
- На уровне веб-сервера — отклоняйте запросы с дубликатами заголовков, независимо от регистра.
- В приложении — используйте API, возвращающие только одно значение заголовка.
- В прокси и CDN — включите строгую нормализацию имён заголовков и проверку уникальности.
- В WAF (например, ModSecurity ) — настройте правила блокировки дубликатов.
Заключение
HTTP Header Injection через дублирование заголовков в разных регистрах — это пример того, как формально безопасная особенность протокола становится уязвимостью из-за несовпадений в реализации. Проблема не в самом регистре, а в том, что разные участники цепочки обработки могут интерпретировать эти заголовки по-разному. Лучшая защита — строгая нормализация на всех уровнях и проверка уникальности каждого заголовка в запросах.