Web Cache Deception WCD — это уязвимость конфигурации кэширующей инфраструктуры, при которой персонализированный ответ приложения ошибочно сохраняется и раздается как общий статический объект. В результате содержимое, зависящее от учетной сессии, становится доступным без аутентификации при обращении по тому же адресу.
Причина возникновения
Кэш на границе сети принимает решение о хранении по ключу кэша и правилам сопоставления. Если политика ориентируется на расширение файла или шаблон пути, а не на заголовки ответа и контекст аутентификации, динамический HTML может быть принят за статический ресурс. Дополнительно риск повышает переписывание путей на уровне прокси или фреймворка, когда разные варианты URL обрабатываются одним и тем же контроллером.
Последовательность эксплуатации
- Манипуляция путем. Злоумышленник формирует адрес вида
/account/statement.css, хотя контроллер обслуживает/account. Роутер игнорирует суффикс и возвращает персональную страницу. - Неверная классификация ответа. Пограничный кэш применяет политику для статического ресурса по признаку расширения и сохраняет ответ, не учитывая куки или заголовок Authorization.
- Повторный доступ без аутентификации. Любой клиент запрашивает тот же адрес и получает ранее сохраненный персональный ответ из кэша.
Предпосылки на стороне инфраструктуры
- Переписывание пути. Один контроллер обрабатывает
/privateи/private/произвольный-хвост.jpg. - Эвристики по расширению. Правила кэширования привязаны к маскам расширений без верификации контекста аутентификации.
- Отсутствие санитизации по авторизации. Система кэширования не исключает из хранения ответы, зависящие от Cookie или Authorization.
- Некорректный ключ кэша. Ключ не учитывает параметры, влияющие на персонализацию, и не привязан к значимым заголовкам.
- Неверные заголовки ответа. На персональных маршрутах отсутствуют директивы Cache-Control no-store либо private и корректный набор заголовков Vary.
Признаки в телеметрии
- Непропорционально высокий показатель кэш-попаданий по префиксам, где ответы зависят от сессии пользователя.
- Рост обращений к адресам с расширениями css js jpg pdf внутри приватных разделов.
- Несоответствие типа контента ответам из кэша например Content-Type text html для путей с расширением статического ресурса.
- Снижение нагрузки на origin при увеличении посещений приватных страниц.
Отличие от Web Cache Poisoning
При Web Cache Poisoning кэш хранит подмененный ответ. При Web Cache Deception кэш хранит корректный по содержанию, но персональный ответ, который не должен был попадать в общий слой.
Правильная политика заголовков
- Cache-Control. Для персональных страниц используйте no-store или private с no-cache. Не полагайтесь на поведение по умолчанию.
- Vary. Если контент зависит от Cookie Authorization локали или географии, перечислите эти параметры в заголовке Vary. Пример Vary Cookie Authorization Accept-Language.
- Явный ключ кэша. Формируйте ключ из нормализованного пути и ограниченного набора параметров и заголовков, которые действительно влияют на тело ответа.
- Negative cache. Короткий TTL для 404 и 403 в приватных разделах уменьшает нагрузку на origin во время перебора вариантов пути.
Распространенные ошибки конфигурации
- Единые регулярные выражения маршрутизации для приватных и статических путей.
- Кэширование по маскам расширений внутри приватных префиксов.
- Отсутствие директив Cache-Control на персональных контроллерах.
- Ключ кэша не учитывает Cookie или Authorization.
- Отсутствие нормализации пути и белого списка расширений для кэшируемой статики.
Рекомендации по архитектуре
Нормализация маршрутов и разграничение контуров
- Статическую отдачу вынести на отдельный префикс или поддомен, обслуживаемый из независимого origin.
- Приватные контроллеры принимать строго фиксированные пути. Любые попытки добавить расширение в приватный путь должны блокироваться на границе до приложения.
- Использовать белый список расширений и явные правила кэширования только для статического префикса.
Санитизация кэша по признаку авторизации
- Если запрос содержит Authorization или сессионный Cookie, кэширования не должно происходить, а ответ приложения должен содержать Cache-Control no-store.
- На уровне CDN и обратного прокси включить байпас кэша при наличии признаков аутентификации.
Формирование ключа кэша
- Включать в ключ только нормализованный путь и ограниченный перечень параметров запроса, влияющих на контент, например параметр версии ресурса.
- Исключать шумовые параметры и нестабильные заголовки.
Negative cache и отказ от эвристик
- Настроить короткий TTL для кодов 404 и 403 в приватных разделах.
- Запретить правила вида если расширение jpg то кэшировать внутри приватных префиксов.
Примеры конфигураций в виде псевдокода
Байпас кэша при авторизации
# edge или reverse proxy if request.headers.contains("Authorization") or request.cookies.contains("session") then cache.bypass() response.headers.set("Cache-Control","no-store") end
Белый список статики
# кэширование только под /static и только разрешенные расширения if path.starts_with("/static/") and ext in [".css",".js",".png",".jpg",".svg",".woff2"] then cache.allow(ttl="24h", key=normalize(path, query=["v"])) else cache.bypass() end
Защита приватных маршрутов от добавления расширений
# блокировка попыток обращения к приватным страницам с суффиксом расширения if path.starts_with("/account/") and path.matches(".(css|js|png|jpg|svg|pdf)$") then return 404 end
Заголовки ответа для персонального HTML
HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Cache-Control: no-store Vary: Cookie, Authorization, Accept-Language
Наблюдаемость и контроль
- Логи кэша с полями ключ кэширования признак попадания причина решения и информация об авторизации.
- Алерт при резком росте кэш-попаданий по приватным префиксам.
- Алерт при несоответствии Content-Type и предполагаемого типа по расширению пути.
- Трассировка с меткой источник ответа кэш или origin для приватных префиксов.
Порядок реагирования
Первые минуты
- Включить байпас кэша для приватных префиксов account user admin.
- Отключить правила кэширования по расширениям внутри приватных префиксов.
- Снизить TTL публичного кэша до безопасного значения и включить revalidate.
Первый час
- Извлечь статистику кэш-попаданий по приватным путям и сопоставить с наличием признаков авторизации.
- Включить negative cache для 404 и 403 и нормализацию пути.
- Выпустить обновления контроллеров с Cache-Control no-store и корректным набором Vary.
Первые сутки
- Разнести статику и динамику на разные домены или зоны кэширования.
- Добавить юнит- и интеграционные тесты, имитирующие обращение к приватным разделам с масками расширений, и проверку поведения кэша для анонимного клиента.
- Задокументировать матрицу кэш-политик для каждого префикса.
Автоматические проверки
В конвейер сборки имеет смысл добавить тест с двумя клиентами. Первый клиент выполняет аутентификацию и получает ответ по адресу вида /account/detail.jpg с фиксацией заголовков и источника ответа. Второй клиент без аутентификации обращается по тому же адресу. Тест считается неуспешным, если второй клиент получает содержимое, отличное от 404 403 или перенаправления на страницу входа.