awesome-everything EN
↑ Обратно к восхождению

Сети и протоколы

Заголовок Vary и cache keys

Суть Как строятся cache keys в CDN, почему Vary: User-Agent уничтожает hit rate, и почему отсутствующий Vary: Cookie может отдать страницу одного пользователя другому.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 12 min

CDN hit rate 5% несмотря на max-age=3600. Dashboard показывает тысячи уникальных записей кеша на URL. Где-то в заголовках ответа origin есть строка Vary, которая молча фрагментирует каждый URL на тысячи отдельных cache keys — по одному на каждую уникальную комбинацию заголовков браузера. Это самая распространённая мисконфигурация CDN в production.

Как строится cache key

CDN-кеш хранит ответы, индексированные по cache key. Ключ по умолчанию: (URL, HTTP method, Host). Заголовок ответа Vary расширяет ключ дополнительными измерениями запроса:

Cache-Control: public, max-age=3600
Vary: Accept-Encoding, Accept-Language

Это говорит кешу: хранить отдельные записи для каждого уникального значения Accept-Encoding и Accept-Language. Запрос /page с Accept-Language: en и другой с Accept-Language: ru создают две отдельные записи кеша — обе правильные языковые версии раздаются из кеша.

RFC 7234 §4.1 формализует это: «Кеш ДОЛЖЕН использовать значение заголовка Vary для определения, может ли хранимый ответ использоваться для данного запроса».

Ловушка Vary

Vary работает корректно для Accept-Encoding (gzip vs brotli — ~5 уникальных значений) и Accept-Language (~10–50 значений на сайт). Но у некоторых заголовков тысячи или миллионы уникальных значений:

Заголовок VaryУникальных значенийЭффект
Accept-Encoding~5 (gzip, br, identity…)Безопасен — небольшая фрагментация
Accept-Language~50 на типичный сайтОбычно нормально
User-AgentТысячи (каждый браузер × версия × ОС)Кеш уничтожен
CookieНа пользователя (миллионы)Эффективно некешируемо
AuthorizationНа авторизованного пользователяЭффективно некешируемо

Vary: User-Agent — классическая ловушка: разработчики добавляют его, чтобы отдавать разный HTML для мобильных и десктопных. Результат: одна запись кеша на каждую уникальную строку User-Agent — каждый релиз Chrome, каждая версия iOS, каждая сборка Safari. Кеш заполняется уникальными записями, которые никогда не используются повторно; hit rate падает к нулю.

Влияние Vary на cache hit rate
Нет Vary (или только Vary: Accept-Encoding)
90–98% hit rate (нормальная работа)
Добавлен Vary: Accept-Language (10 значений)
80–90% — небольшая фрагментация
Добавлен Vary: User-Agent
<10% — почти нулевое кеширование
Добавлен Vary: Cookie
~0% — записи на пользователя никогда не переиспользуются
Добавлен Vary: Authorization
~0% — записи на токен никогда не переиспользуются

Сюрпризы cache key

1/3

Cookies не входят в cache key по умолчанию

Это самый важный с точки зрения безопасности факт про Vary. Cookies не являются частью cache key по умолчанию. Если endpoint читает session cookie и возвращает персонализированный контент:

  • Отсутствие Cache-Control: private → CDN кеширует персонализированный ответ
  • Отсутствие Vary: Cookie → разные пользователи с разными cookies получают один закешированный ответ

Результат: страница аккаунта одного пользователя раздаётся другому — утечка данных.

Правило: для любого endpoint, читающего cookie, задавайте Cache-Control: private. Используйте Vary: Cookie только если нужен CDN-кеш для контента, различающегося по cookie (редко, сложно, требует cookie с стабильным и низкокардинальным значением).

Граничные случаи

Cache poisoning через некешируемые заголовки. Исследование Джеймса Кеттла (PortSwigger, 2018) задокументировало, как CDN можно обмануть, заставив кешировать вредоносный ответ. Если origin читает заголовок запроса (например, X-Forwarded-Host) для формирования тела ответа, но этот заголовок НЕ входит в cache key CDN (нет в Vary), атакующий может отправить запрос с X-Forwarded-Host: evil.com — origin возвращает страницу со ссылками на evil.com, CDN кеширует её только по URL и раздаёт отравленную страницу всем последующим пользователям. Защита: согласовать CDN и origin, какие заголовки значимы для ключа; удалять нераспознанные forwarding-заголовки на edge CDN; использовать нормализацию cache key для отброса незначимых query-параметров.

Викторина

Что делает Vary: Accept-Encoding в кеше CDN?

Викторина

Каков практический эффект Vary: Authorization в shared CDN-кеше?

Расставь шаги по порядку

Упорядочите значения Vary от наиболее безопасного (минимальная фрагментация) к наиболее опасному (максимальная):

  1. 1 Vary: Accept-Encoding — ~5 уникальных значений (gzip, brotli, identity, deflate, none)
  2. 2 Vary: Accept-Language — ~10–50 значений на типичный сайт
  3. 3 Vary: Accept — согласование типа контента, ~5–10 значений
  4. 4 Vary: User-Agent — тысячи уникальных значений по браузерам и версиям
  5. 5 Vary: Cookie — потенциально миллионы уникальных значений (по одному на активную сессию)
Вспомните перед уходом
  1. 01
    Объясните, почему Vary: Accept-Encoding обязателен для endpoint, отдающего gzip-ответы одним клиентам и несжатые — другим.
  2. 02
    Страница статьи новостного сайта имеет Vary: User-Agent для разных макетов мобильных и десктопных. Cache hit rate 3%. В чём корневая причина и как исправить?
  3. 03
    Почему cookies не входят в cache key CDN по умолчанию и какой риск безопасности это создаёт?
Итог

Cache key CDN строится из URL, HTTP-метода, Host и заголовков запроса, перечисленных в Vary ответа. Vary: Accept-Encoding безопасен — ~5 возможных значений. Vary: Accept-Language обычно безопасен — ~10–50 значений. Vary: User-Agent катастрофичен — тысячи уникальных комбинаций браузер×версия×ОС, каждая становится отдельной записью кеша, которая никогда не переиспользуется, обрушивая hit rate к нулю. Cookies НЕ входят в ключ по умолчанию — это выбор в пользу эффективности, создающий риск безопасности: endpoints с персонализированным контентом без Cache-Control: private могут отдать ответ одного пользователя другому. Проверяйте каждый роут, читающий cookies или auth-заголовки, и помечайте его private или no-store.

Связанные уроки
встречается в162
Продолжить восхождение ↑Stale-while-revalidate и cache stampede
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.