Смерть third-party cookies. Что ждет нас в 2024?

9f31eb9a6ca6798cd742a70a085fa6b1

О чем речь?

Похоже, что в череде всевозможных инициатив по борьбе со «сторонними» куками начал проглядываться конец. Давайте разберемся, что происходит и зачем все это нужно.

Куки — браузерный механизм, который позволяет хранить данные по пользователю с привязкой к домену и затем передавать эти данные при запросах. Куку можно установить как со стороны сервера через специальный заголовок Set‑Cookie, так и в браузере прямо на странице через javascript. После этого кука будет передаваться при каждом запросе из браузера к домену.

Куки позволяют воплощать в жизнь множество как полезных, так и сомнительных механик. Из неприятных — возможность отслеживания пользователя сторонними сайтами или увеличение риска CSRF.

Как это работает сейчас?

First‑party куки — это куки того сайта, который открыт в вашем браузере (его домен вы видите в адресной строке). Thirt‑party — это куки запросов, которые ходят за данными на другие домены (загрузка картинок и скриптов с CDN, запросы за рекламой). Легко догадаться, что если какой‑то сервис установил свои скрипты на большинстве сайтов, то отслеживание пользователей для него остается лишь делом техники.

Помимо разделения на first и third‑party для нас также важно разделение на 3 режима работы кук с точки зрения разграничения по сайтам (чуть позже для нас это станет важно). Эти режимы работы регулируется параметром SameSite:

  • SameSite=None означает, что кука не привязана к сайту. После того как она выставлена, она будет передаваться как в first‑party, так и в third‑party режиме.

  • SameSite=Strict означает, что кука передается только в first‑party режиме (пока находишься на сайте)

  • SameSite=Lax работает примерно как Strict за тем исключением, что кука отправляется еще и при навигации в браузере (при запросе за исходным HTML)

В большинстве браузеров уже есть те или иные механизмы блокировки third‑party кук. В одних браузерах это ограничивается тем, что third‑party куки разрешено отправлять только на посещенные пользователем сайты. В других браузерах внедряют различные «enhanced» и «intellegent» tracking protection,  либо совсем блокируют third‑paty куки. Для тех, кто захочет разобраться детально в перипетиях отдельных браузеров, есть прекрасные статьи.

В 2019 году волей сообщества дефолтное поведение кук в браузерах изменилось с SameSite=None на SameSite=Lax. Что, впрочем, привело лишь к тому, что большинство сервисов перевело свои трекеры в режим SameSite=None.

Консенсус в сообществе свелся к тому, что:
— Нужно запретить отслеживать пользователя между сайтами
— First‑party — это вполне ОК. Сайт внутри себя может позволить себе любые манипуляции с пользовательскими данными
— Third‑party — в целом тоже ОК, но только если ограничить third‑party куки одним сайтом (следите за руками ниже)

Так какие же есть решения для того, чтобы отказаться от third‑party кук и ничего не сломать?

Какие есть решения?

На данный момент механизма разграничения third‑party кук не существует, поэтому для решения проблемы была изобретена еще одна «фича» — Cookies Having Independent Partitioned State (CHIPS). «Чипсы» (CHIPS) приходят на замену «печенек» (Cookies), кек. В рамках этой фичи у кук появляется еще один атрибут — Partitioned. Кука с таким атрибутом будет отправляться только с того сайта, на котором она была выставлена.

Например, пользователь заходит на сайт https://first-site.com. Сайт загружает картинку с https://avatars.com. В ответ https://avatars.com отправляет заголовок Set-Cookie с атрибутом Partitioned. Эта кука будет отправляться из браузера при каждом запросе к https://avatars.com с сайта https://first-site.com. Однако когда пользователь зайдет на другой сайт https://second-site.com и попытается загрузить ту же картинку с сайта https://avatars.com, имеющаяся кука уже не будет отправлена. Вместо этого сервер может выставить для пользователя новую куку с атрибутом Partitioned, которая будет отправляться только с сайта https://second-site.com.

При этом внедрение Partitioned кук подразумевает постепенный отказ от всех остальных third‑party кук. Все куки, работающие в режиме SameSite=None без выставленного атрибута Partitioned просто перестанут отправляться из third‑party окружения. Именно перестанут отправляться, а не просто будут сконвертированы в Partitioned. Гугл планирует раскатить эту фичу в 2 этапа — на 1% пользователей хрома с января 2024 и на 100% пользователей осенью 2024.

Это сломает множество сценариев использования сайтов. Очень часто сайтам нужно шарить куку между доменами (например между google.com и google.ru). Для того чтобы дать сайтам такую возможность,  была изобретена еще одна «фича» — Storage Access API (SAA). Она позволит получить доступ к SameSite=None куке без атрибута Partitioned для запросов из third‑party окружения, но только с явного разрешения браузера или пользователя.

Как пример — я захожу на сайт first-site.com, на котором встроена авторизация через сторонний сервис authorization.com. Сайт встраивает iframe стороннего сервиса. Внутри iframe вызывается скрипт, который проверяет, может ли он получить доступ к своей SameSite=None куке. Проверка происходит через вызов await navigator.permissions.query({name: 'storage-access'}). Если пользователь ни разу не был на сайте authorization.com, или окружение не соответствует другим критериям — получаем отказ. Пример того, как это должно работать, лежит тут. Если промис резолвится с объектом { state: 'prompt' }, значит для получения доступа к SameSite=None куке необходимо спросить разрешение у пользователя.

После этого можно запросить разрешение через вызов await document.requestStorageAccess(). При необходимости апрува пользователя, prompt будет выглядеть примерно так:

authorization.com wants to use info they’ve saved about you
authorization.com will know that you visited first‑site.com.
Learn more about embedded content

Промис резолвится — значит у нас появился доступ к SameSite=None кукам authorization.com (как через document.cookie, так и к HttpOnly кукам при запросах из айфрейма). Реджект — извините.

При каждом обновлении страницы доступ к кукам необходимо перезапрашивать через requestStorageAccess. Prompt показывается только один раз (последующие разы разрешение выдается автоматически).

Все, что написано ниже, мне удалось найти в документации, но не посчастливилось проверить своими руками. Если вам удастся, напишите в комментариях:)

Так, ну с iframe проблема, хоть и неудобно, но решается. А как быть с ресурсами типа картинок, которые не могут подгрузить для себя скрипт и запросить разрешение? Для таких случаев разработчики Chrome придумали еще одну «фичу» — requestStorageAccessFor. Это API позволяет сделать «обратный финт» — запросить доступ к кукам не с самого домена, а «для» домена. Например, я захожу на сайт first-site.com и собираюсь загрузить аватарку с домена avatars.com. Прежде, чем начать загрузку, я запрашиваю разрешение через await document.requestStorageAccessFor('https://avatars.com'). Если все успешно — при запросе за картинкой отправятся SameSite=None куки с домена avatars.com.

Chrome также внедряет еще одну полезную «фичу», про которую нужно знать. Related Website Sets (RWS) позволяет создавать группы сайтов с общими куками. Для того чтобы это заработало — нужно буквально закоммитить список своих сайтов в специальный файлик на гитхабе. В этом файле указывается primary сайт, associatedSites — которые являются неотъемлемой частью сервиса и требуют обмена пользовательскими данными, а также их ccTLDs для разных регионов. Чтобы подтвердить свои благородные намерения, необходимо добавить на свой сайт файлик /.well-known/related-website-set.json с теми же данными. Если вы сделали все правильно, вам не нужно будет запрашивать разрешение у пользователя для обмена куками.

© Habrahabr.ru