Обеспечение безопасности и конфиденциальности путем разделения кеша

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

В Chrome механизм кэширования используется различными способами, и HTTP-кеширование является одним из примеров.

Как в настоящее время работает HTTP-кэш Chrome

Начиная с версии 85, Chrome кэширует ресурсы, полученные из сети, используя соответствующие URL-адреса ресурсов в качестве ключа кэша. (Ключ кэша используется для идентификации кэшированного ресурса.)

Следующий пример иллюстрирует, как одно изображение кэшируется и обрабатывается в трех различных контекстах:

Ключ кэша: https://x.example/doge.png
Ключ кэша : { https://x.example/doge.png }

Пользователь посещает страницу ( https://a.example ), которая запрашивает изображение ( https://x.example/doge.png ). Изображение запрашивается из сети и кэшируется с использованием https://x.example/doge.png в качестве ключа.

Ключ кэша: https://x.example/doge.png
Ключ кэша : { https://x.example/doge.png }

Тот же пользователь посещает другую страницу ( https://b.example ), которая запрашивает то же изображение ( https://x.example/doge.png ). Браузер проверяет свой HTTP-кэш, чтобы узнать, есть ли у него уже кэшированный ресурс, используя URL-адрес изображения в качестве ключа. Браузер находит совпадение в своем кэше, поэтому он использует кэшированную версию ресурса.

Ключ кэша: https://x.example/doge.png
Ключ кэша : { https://x.example/doge.png }

Неважно, загружено ли изображение из iframe. Если пользователь посещает другой веб-сайт ( https://c.example ) с iframe ( https://d.example ) и iframe запрашивает то же изображение ( https://x.example/doge.png ), браузер все равно может загрузить изображение из своего кэша, поскольку ключ кэша одинаков для всех страниц.

Этот механизм хорошо работает с точки зрения производительности уже долгое время. Однако время, которое требуется веб-сайту для ответа на HTTP-запросы, может показать, что браузер обращался к тому же ресурсу в прошлом, что делает браузер уязвимым для атак на безопасность и конфиденциальность, например:

  • Определите, посещал ли пользователь определенный сайт : злоумышленник может определить историю просмотров пользователя, проверив, есть ли в кэше ресурс, который может быть специфичен для определенного сайта или группы сайтов.
  • Атака с использованием межсайтового поиска : злоумышленник может определить, содержится ли произвольная строка в результатах поиска пользователя, проверив, находится ли в кэше браузера изображение «Нет результатов поиска», используемое определенным веб-сайтом.
  • Межсайтовое отслеживание : кэш может использоваться для хранения идентификаторов, подобных файлам cookie, в качестве механизма межсайтового отслеживания.

Чтобы снизить эти риски, Chrome, начиная с версии Chrome 86, разделяет свой HTTP-кэш.

Как разбиение кэша повлияет на HTTP-кеш Chrome?

При разделении кэша кэшированные ресурсы будут зашифрованы с использованием нового «ключа сетевой изоляции» в дополнение к URL-адресу ресурса. Ключ сетевой изоляции состоит из сайта верхнего уровня и сайта текущего кадра.

Еще раз взгляните на предыдущий пример, чтобы увидеть, как работает разбиение кэша в различных контекстах:

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://a.example , https://a.example , https://x.example/doge.png }

Пользователь посещает страницу ( https://a.example ), которая запрашивает изображение ( https://x.example/doge.png ). В этом случае изображение запрашивается из сети и кэшируется с использованием кортежа, состоящего из https://a.example (сайт верхнего уровня), https://a.example (сайт текущего кадра) и https://x.example/doge.png (URL ресурса) в качестве ключа. (Обратите внимание, что когда запрос ресурса поступает из фрейма верхнего уровня, сайт верхнего уровня и сайт текущего кадра в ключе сетевой изоляции совпадают.)

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://b.example , https://b.example , https://x.example/doge.png }

Тот же пользователь посещает другую страницу ( https://b.example ), которая запрашивает то же изображение ( https://x.example/doge.png ). Хотя то же изображение было загружено в предыдущем примере, поскольку ключ не совпадает, это не будет кэш-попаданием.

Изображение запрашивается из сети и кэшируется с использованием кортежа, состоящего из https://b.example , https://b.example и https://x.example/doge.png в качестве ключа.

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://a.example , https://a.example , https://x.example/doge.png }

Теперь пользователь возвращается на https://a.example , но на этот раз изображение ( https://x.example/doge.png ) встроено в iframe. В этом случае ключом является кортеж, содержащий https://a.example , https://a.example и https://x.example/doge.png , и происходит попадание в кэш. (Обратите внимание, что когда сайт верхнего уровня и iframe являются одним и тем же сайтом, можно использовать ресурс, кэшированный с фреймом верхнего уровня.

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://a.example , https://c.example , https://x.example/doge.png }

Пользователь вернулся на https://a.example , но на этот раз изображение размещено в iframe с https://c.example .

В этом случае изображение загружается из сети, поскольку в кэше нет ресурса, соответствующего ключу, состоящему из https://a.example , https://c.example и https://x.example/doge.png .

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://a.example , https://c.example , https://x.example/doge.png }

Что делать, если домен содержит поддомен или номер порта? Пользователь посещает https://subdomain.a.example , который встраивает iframe ( https://c.example:8080 ), который запрашивает изображение.

Поскольку ключ создан на основе "scheme://eTLD+1", поддомены и номера портов игнорируются. Следовательно, происходит попадание в кэш.

Ключ кэша { https://a.example, https://a.example, https://x.example/doge.png}
Ключ кэша : { https://a.example , https://c.example , https://x.example/doge.png }

Что делать, если iframe вложен несколько раз? Пользователь посещает https://a.example , который встраивает iframe ( https://b.example ), который встраивает еще один iframe ( https://c.example ), который в конечном итоге запрашивает изображение.

Поскольку ключ берется из верхнего фрейма ( https://a.example ) и непосредственного фрейма, который загружает ресурс ( https://c.example ), происходит попадание в кэш.

Часто задаваемые вопросы

Включено ли это уже в моем Chrome? Как я могу проверить?

Функция будет развернута до конца 2020 года. Чтобы проверить, поддерживает ли ее ваш экземпляр Chrome:

  1. Откройте chrome://net-export/ и нажмите «Начать запись на диск» .
  2. Укажите, где на вашем компьютере сохранить файл журнала.
  3. Полистайте веб-страницы в Chrome в течение минуты.
  4. Вернитесь на chrome://net-export/ и нажмите «Остановить ведение журнала» .
  5. Перейдите по ссылке https://netlog-viewer.appspot.com/#import .
  6. Нажмите «Выбрать файл» и передайте сохраненный вами файл журнала.

Вы увидите вывод файла журнала.

На той же странице найдите SplitCacheByNetworkIsolationKey . Если за ним следует Experiment_[****] , то HTTP-разделение кэша включено в вашем Chrome. Если за ним следует Control_[****] или Default_[****] , то оно не включено.

Как протестировать разбиение HTTP-кэша на Chrome?

Чтобы протестировать разделение HTTP-кэша на Chrome, вам нужно запустить Chrome с флагом командной строки: --enable-features=SplitCacheByNetworkIsolationKey . Следуйте инструкциям в разделе Запуск Chromium с флагами , чтобы узнать, как запустить Chrome с флагом командной строки на вашей платформе.

Должен ли я как веб-разработчик предпринять какие-либо действия в ответ на это изменение?

Это не критическое изменение, но оно может повлиять на производительность некоторых веб-сервисов.

Например, те, кто обслуживает большие объемы высококэшируемых ресурсов на многих сайтах (таких как шрифты и популярные скрипты), могут заметить рост своего трафика. Кроме того, те, кто потребляет такие услуги, могут иметь повышенную зависимость от них.

(Существует предложение о включении общих библиотек с сохранением конфиденциальности, называемое Web Shared Libraries ( видеопрезентация ), но оно все еще находится на рассмотрении.)

Каковы последствия этого изменения поведения?

Общий показатель промахов кэша увеличивается примерно на 3,6%, изменения FCP (First Contentful Paint) незначительны (~0,3%), а общая доля байтов, загружаемых из сети, увеличивается примерно на 4%. Подробнее о влиянии на производительность можно узнать в пояснении кеширования HTTP .

Это стандартизировано? Другие браузеры ведут себя по-другому?

«Разделы кэша HTTP» стандартизированы в спецификации fetch, хотя браузеры ведут себя по-разному:

Как обрабатывается прием от рабочих?

Выделенные рабочие используют тот же ключ, что и их текущий фрейм. Работники служб и общие рабочие сложнее, поскольку они могут быть общими для нескольких сайтов верхнего уровня. Решение для них в настоящее время обсуждается.

Ресурсы