API доступа к хранилищу

Блокировка сторонних файлов cookie с помощью браузеров, пользовательских настроек и разделения хранилища представляет собой проблему для сайтов и служб, которые полагаются на файлы cookie и другие хранилища во встроенных контекстах для таких действий пользователя, как аутентификация. API доступа к хранилищу (SAA) позволяет этим вариантам использования продолжать работать, максимально ограничивая межсайтовое отслеживание.

Статус реализации

Browser Support

  • Хром: 119.
  • Край: 85.
  • Фаерфокс: 65.
  • Сафари: 11.1.

Source

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

Продолжается работа над решением всех оставшихся проблем с блокировкой перед стандартизацией API .

Что такое API доступа к хранилищу?

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

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

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

Варианты использования

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

Варианты использования включают в себя:

  • Встроенные виджеты комментариев, для которых требуются данные сеанса входа в систему.
  • Кнопки «Мне нравится» в социальных сетях, для которых требуются данные сеанса входа в систему.
  • Встроенные документы, для которых требуются данные сеанса входа в систему.
  • Премиум-возможности, предоставляемые при встраивании видео (например, чтобы не показывать рекламу вошедшим в систему пользователям или знать предпочтения пользователя в отношении субтитров или ограничивать определенные типы видео).
  • Встроенные платежные системы.

Многие из этих вариантов использования включают сохранение доступа для входа во встроенные iframe.

Когда использовать API доступа к хранилищу вместо других API

API доступа к хранилищу — это одна из альтернатив использованию неразделенных файлов cookie и хранилища, поэтому важно понимать, когда использовать этот API по сравнению с другими. Он предназначен для случаев использования, когда справедливы оба следующих условия:

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

Существуют альтернативные API для различных случаев использования:

  • Файлы cookie с независимым разделенным состоянием (CHIPS) позволяют разработчикам включать файлы cookie в «разделенное» хранилище с отдельной банкой файлов cookie для каждого сайта верхнего уровня. Например, сторонний виджет веб-чата может использовать установку файла cookie для сохранения информации о сеансе. Информация о сеансе сохраняется для каждого сайта, поэтому к файлу cookie, установленному виджетом, нет необходимости обращаться на других веб-сайтах, где он также встроен. API доступа к хранилищу полезен, когда встроенный сторонний виджет зависит от совместного использования одной и той же информации в разных источниках (например, для сведений о сеансе входа или предпочтений).
  • Разделение хранилища — это способ межсайтовых iframe использовать существующие механизмы хранения JavaScript при разделении базового хранилища для каждого сайта. Это предотвращает доступ к встроенному хранилищу на одном веб-сайте с помощью той же вставки на других веб-сайтах.
  • Наборы связанных веб-сайтов (RWS) — это способ для организации объявить взаимосвязи между сайтами, чтобы браузеры разрешали ограниченный доступ к неразделенным файлам cookie и хранилищу для определенных целей. Сайтам по-прежнему необходимо запрашивать доступ с помощью API доступа к хранилищу, но для сайтов в наборе доступ может быть предоставлен без запросов пользователя.
  • Федеративное управление учетными данными (FedCM) — это подход к федеративным службам идентификации, обеспечивающий сохранение конфиденциальности. API доступа к хранилищу обеспечивает доступ к неразделенным файлам cookie и хранилищу после входа в систему. В некоторых случаях использования FedCM предоставляет альтернативное решение API доступа к хранилищу и может быть предпочтительнее, поскольку оно имеет более ориентированное на вход приглашение браузера. Однако внедрение FedCM обычно требует дополнительных изменений в вашем коде, например, для поддержки конечных точек HTTP.
  • Также существуют API для защиты от мошенничества , рекламы и измерения , и API доступа к хранилищу не предназначен для решения этих проблем.

Используйте API доступа к хранилищу

API доступа к хранилищу имеет два метода на основе обещаний:

Он также интегрируется с API разрешений . Это позволяет вам проверить статус разрешения на доступ к хранилищу в стороннем контексте, который указывает, будет ли автоматически разрешен вызов document.requestStorageAccess() :

Используйте метод hasStorageAccess()

При первой загрузке сайта он может использовать метод hasStorageAccess() , чтобы проверить, предоставлен ли уже доступ к сторонним файлам cookie.

// Set a hasAccess boolean variable which defaults to false.
let hasAccess = false;

async function handleCookieAccessInit() {
  if (!document.hasStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    hasAccess = true;
  } else {
    // Check whether access has been granted using the Storage Access API.
    // Note on page load this will always be false initially so we could be
    // skipped in this example, but including for completeness for when this
    // is not so obvious.
    hasAccess = await document.hasStorageAccess();
    if (!hasAccess) {
      // Handle the lack of access (covered later)
    }
  }
  if (hasAccess) {
    // Use the cookies.
  }
}
handleCookieAccessInit();

Доступ к хранилищу предоставляется документу iframe только после того, как он вызывает requestStorageAccess(), поэтому hasStorageAccess() изначально всегда возвращает false — за исключением случаев, когда другому документу того же происхождения в том же iframe уже был предоставлен доступ. Предоставление сохраняется при навигации по тому же источнику внутри iframe специально для того, чтобы разрешить перезагрузку после предоставления доступа к страницам, для которых требуется присутствие файлов cookie в первоначальном запросе HTML-документа.

Используйте requestStorageAccess()

Если у iframe нет доступа, возможно, ему потребуется запросить доступ с помощью метода requestStorageAccess() :

if (!hasAccess) {
  try {
    await document.requestStorageAccess();
  } catch (err) {
    // Access was not granted and it may be gated behind an interaction
    return;
  }
}

При первом запросе пользователю может потребоваться подтвердить этот доступ с помощью запроса браузера, после чего обещание будет разрешено или будет отклонено, что приведет к исключению, если используется await .

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

async function doClick() {

  // Only do this extra check if access hasn't already been given
  // based on the hasAccess variable.
  if (!hasAccess) {
    try {
      await document.requestStorageAccess();
      hasAccess = true; // Can assume this was true if requestStorageAccess() did not reject.
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  if (hasAccess) {
    // Use the cookies
  }
}

document.querySelector('#my-button').addEventListener('click', doClick);

Если вам нужно использовать локальное хранилище вместо файлов cookie, вы можете сделать следующее:

let handle = null;

async function doClick() {
  if (!handle) {
    try {
      handle = await document.requestStorageAccess({localStorage: true});
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  // Use handle to access unpartitioned local storage.
  handle.localStorage.setItem('foo', 'bar');
}

document.querySelector('#my-button').addEventListener('click', doClick);

Запросы на разрешение

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

Запрос разрешения API доступа к хранилищу Chrome
Запрос разрешения API доступа к хранилищу Chrome

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

  • Если страница и iframe использовались в течение последних 30 дней после принятия запроса.
  • Если встроенный iframe является частью набора связанных веб-сайтов .
  • Если FedCM используется в качестве сигнала доверия для доступа к хранилищу.
  • В Firefox приглашение также пропускается для известных веб-сайтов (тех, с которыми вы взаимодействовали на верхнем уровне) в течение первых пяти попыток.

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

  • Если пользователь ранее не посещал и не взаимодействовал с сайтом, которому принадлежит iframe как документ верхнего уровня, а не в iframe. Это означает, что API доступа к хранилищу полезен только для встроенных сайтов, которые пользователи ранее посещали в собственном контексте.
  • Если метод requestStorageAccess() вызывается вне события взаимодействия с пользователем без предварительного утверждения запроса после взаимодействия.

Хотя пользователю будет предложено при первом использовании, последующие посещения могут разрешить requestStorageAccess() без запроса и без вмешательства пользователя в Chrome и Firefox. Обратите внимание, что Safari всегда требует взаимодействия с пользователем.

Поскольку доступ к файлам cookie и хранилищу может быть предоставлен без запроса или взаимодействия с пользователем, часто можно получить неразделенный доступ к файлам cookie или хранилищу до взаимодействия с пользователем в браузерах, которые это поддерживают (Chrome и Firefox), вызвав requestStorageAccess() при загрузке страницы. Это может позволить вам получить немедленный доступ к неразделенным файлам cookie и хранилищу и обеспечить более полный опыт, даже до того, как пользователь начнет взаимодействовать с iframe. В некоторых ситуациях это может оказаться более удобным для пользователя, чем ожидание взаимодействия с пользователем.

FedCM как сигнал доверия для SAA

FedCM (федеративное управление учетными данными) — это подход к федеративным службам идентификации, обеспечивающий сохранение конфиденциальности (например, «Войти с помощью...»), который не использует сторонние файлы cookie или навигационные перенаправления.

Когда пользователь входит в систему проверяющей стороны (RP), которая имеет встроенный контент от стороннего поставщика удостоверений (IdP) с помощью FedCM, встроенный контент IdP может автоматически получить доступ к хранилищу своих собственных неразделенных файлов cookie верхнего уровня. Чтобы включить автоматический доступ к хранилищу с помощью FedCM, должны быть выполнены следующие условия:

  • Аутентификация FedCM (состояние входа пользователя) должна быть активной.
  • RP согласился, установив разрешение identity-credentials-get , например:
<iframe src="https://idp.example" allow="identity-credentials-get"></iframe>

Например, iframe idp.example встроен в rp.example . Когда пользователь входит в систему с помощью FedCM, iframe idp.example может запросить доступ к хранилищу для своих собственных файлов cookie верхнего уровня.

rp.example выполняет вызов FedCM для входа пользователя в систему с помощью поставщика удостоверений idp.example :

// The user will be asked to grant FedCM permission.
const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/fedcm.json',
      clientId: '123',
    }],
  },
});

После входа пользователя в систему IdP может вызвать requestStorageAccess() из iframe idp.example , если RP явно разрешил это с помощью Permissions Policy . Встроенному файлу будет автоматически предоставлен доступ к хранилищу его собственного файла cookie верхнего уровня без активации пользователя или необходимости получения другого запроса на разрешение :

// Make this call within the embedded IdP iframe:

// No user gesture is needed, and the storage access will be auto-granted.
await document.requestStorageAccess();

// This returns `true`.
const hasAccess = await document.hasStorageAccess();

Разрешение будет предоставлено автоматически только в том случае, если пользователь вошел в систему с помощью FedCM. Если аутентификация неактивна, для предоставления доступа к хранилищу применяются стандартные требования SAA .

Используйте запрос разрешения storage-access

Чтобы проверить, можно ли предоставить доступ без взаимодействия с пользователем, вы можете проверить статус разрешения storage-access и выполнить вызов requestStoreAccess() раньше, если никаких действий пользователя не требуется, вместо того, чтобы вызывать его и вызывать сбой при взаимодействии. требуется.

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

Следующий код добавляет проверку разрешений storage-access к предыдущему примеру:

// Set a hasAccess boolean variable which defaults to false except for
// browsers which don't support the API - where we assume
// such browsers also don't block third-party cookies.
let hasAccess = false;

async function hasCookieAccess() {
  // Check if Storage Access API is supported
  if (!document.requestStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    return true;
  }

  // Check if access has already been granted
  if (await document.hasStorageAccess()) {
    return true;
  }

  // Check the storage-access permission
  // Wrap this in a try/catch for browsers that support the
  // Storage Access API but not this permission check
  // (e.g. Safari and earlier versions of Firefox).
  let permission;
  try {
    permission = await navigator.permissions.query(
      {name: 'storage-access'}
    );
  } catch (error) {
    // storage-access permission not supported. Assume no cookie access.
    return false;
  }

    if (permission) {
    if (permission.state === 'granted') {
      // Permission has previously been granted so can just call
      // requestStorageAccess() without a user interaction and
      // it will resolve automatically.
      try {
        await document.requestStorageAccess();
        return true;
      } catch (error) {
        // This shouldn't really fail if access is granted, but return false
        // if it does.
        return false;
      }
    } else if (permission.state === 'prompt') {
      // Need to call requestStorageAccess() after a user interaction
      // (potentially with a prompt). Can't do anything further here,
      // so handle this in the click handler.
      return false;
          } else if (permission.state === 'denied') {
            // Not used: see https://github.com/privacycg/storage-access/issues/149
      return false;
          }
    }

  // By default return false, though should really be caught by earlier tests.
  return false;
}

async function handleCookieAccessInit() {
  hasAccess = await hasCookieAccess();

  if (hasAccess) {
    // Use the cookies.
  }
}

handleCookieAccessInit();

Изолированные iframe в песочнице

При использовании API доступа к хранилищу в изолированных iframes требуются следующие разрешения песочницы:

  • Для разрешения доступа к API доступа к хранилищу требуется allow-storage-access-by-user-activation .
  • allow-scripts необходим, чтобы разрешить использование JavaScript для вызова API.
  • allow-same-origin требуется, чтобы разрешить доступ к файлам cookie того же происхождения и другим хранилищам.

Например:

<iframe sandbox="allow-storage-access-by-user-activation
                 allow-scripts
                 allow-same-origin"
        src="..."></iframe>

Чтобы к межсайтовым файлам cookie можно было получить доступ с помощью API доступа к хранилищу в Chrome, необходимо установить следующие два атрибута:

  • SameSite=None — требуется, чтобы пометить файл cookie как межсайтовый.
  • Secure — обеспечивает доступ только к файлам cookie, установленным сайтами HTTPS.

В Firefox и Safari для файлов cookie по умолчанию установлено значение SameSite=None , и они не ограничивают SAA для Secure файлов cookie, поэтому эти атрибуты не являются обязательными. Рекомендуется явно указывать атрибут SameSite и всегда использовать Secure файлы cookie.

Доступ к странице верхнего уровня

API доступа к хранилищу предназначен для обеспечения доступа к сторонним файлам cookie во встроенных iframe.

Существуют также другие случаи использования, когда страница верхнего уровня требует доступа к сторонним файлам cookie. Например, изображения или скрипты, использование которых ограничено файлами cookie, и которые владельцы сайтов могут захотеть включить непосредственно в документ верхнего уровня, а не в iframe. Чтобы решить эту проблему, Chrome предложил расширение API доступа к хранилищу , которое добавляет метод requestStorageAccessFor() .

Метод requestStorageAccessFor()

Browser Support

  • Хром: 119.
  • Край: 119.
  • Firefox: не поддерживается.
  • Сафари: не поддерживается.

Source

Метод requestStorageAccessFor() работает аналогично requestStorageAccess() но для ресурсов верхнего уровня. Его можно использовать только для сайтов в наборе связанных веб-сайтов , чтобы предотвратить предоставление общего доступа к сторонним файлам cookie.

Подробнее о том, как использовать requestStorageAccessFor() читайте в разделе «Наборы связанных веб-сайтов: руководство для разработчиков» .

Запрос разрешения top-level-storage-access

Browser Support

  • Хром: не поддерживается.
  • Край: не поддерживается.
  • Firefox: не поддерживается.
  • Сафари: не поддерживается.

Подобно разрешению storage-access , существует разрешение top-level-storage-access позволяющее проверить, можно ли предоставить доступ для requestStorageAccessFor() .

Чем отличается API доступа к хранилищу при использовании с RWS?

Когда наборы связанных веб-сайтов используются с API доступа к хранилищу, доступны определенные дополнительные возможности, подробно описанные в следующей таблице:

Без РВС С РВС
Требуется жест пользователя, чтобы инициировать запрос на доступ к хранилищу
Требуется, чтобы пользователь посетил запрошенное хранилище в контексте верхнего уровня, прежде чем предоставить доступ.
Запрос пользователя при первом посещении можно пропустить.
requestStorageAccess не требуется вызывать, если доступ был ранее предоставлен
Автоматически предоставляет доступ к другим доменам на связанном веб-сайте.
Поддерживает requestStorageAccessFor для доступа к страницам верхнего уровня.
Различия между использованием API доступа к хранилищу без и с наборами связанных веб-сайтов

Демо: настройка и доступ к файлам cookie

В следующей демонстрации показано, как можно получить доступ к файлу cookie, установленному вами на первом экране демонстрации, во встроенном фрейме на втором сайте демонстрации:

хранилище-доступ-api-demo.glitch.me

Для демонстрации требуется браузер с отключенными сторонними файлами cookie:

  • Chrome 118 или более поздней версии с установленным chrome://flags/#test-third-party-cookie-phaseout и перезапущенным браузером.
  • Firefox
  • Сафари

Демо: настройка локального хранилища

В следующей демонстрации показано, как получить доступ к неразделенным широковещательным каналам из стороннего iframe с помощью API доступа к хранилищу:

https://saa-beyond-cookies.glitch.me/

Для демонстрации требуется Chrome 125 или более поздней версии с включенным флагом поэтапного отказа от сторонних файлов cookie .

Ресурсы