Storage Access API

Chrome は、クロスサイト トラッキングを減らすために、サードパーティ Cookie のサポート終了ストレージのパーティショニングを段階的に廃止します。このことは、認証などのユーザー ジャーニーにおいて、埋め込みコンテキストで Cookie などのストレージに依存するサイトやサービスにとって課題となります。Storage Access API(SAA)を使用すると、クロスサイト トラッキングを可能な限り制限しながら、これらのユースケースを引き続き機能させることができます。

実装ステータス

対応ブラウザ

  • 119
  • 85
  • 65
  • 11.1

ソース

Storage Access API はすべての主要なブラウザで利用できますが、ブラウザによって実装に若干の違いがあります。これらの違いについては、この投稿の関連セクションで取り上げています。

API の標準化の前に、残っている問題をすべて解決する取り組みが継続されています。

Storage Access API とは

Storage Access API は、ブラウザの設定でアクセスが拒否される場合に、iframe がストレージへのアクセス権限をリクエストできるようにする JavaScript API です。クロスサイト リソースの読み込みに依存するユースケースを含む埋め込みでは、必要に応じて API を使用してユーザーにアクセス権をリクエストできます。

ストレージ リクエストが許可されると、iframe はパーティション分割されていない Cookie とストレージにアクセスできるようになります。これらの Cookie とストレージは、ユーザーがトップレベル サイトとしてアクセスする場合にも使用できます。

Storage Access API を使用すると、エンドユーザーの負担を最小限に抑えながら、特定のパーティション分割されていない Cookie とストレージへのアクセスを提供すると同時に、ユーザーのトラッキングでよく使われるようなパーティション分割されていない一般的な Cookie やストレージへのアクセスを防止できます。

ユースケース

一部のサードパーティ埋め込みでは、ユーザー エクスペリエンスを向上させるために、パーティション分割されていない Cookie またはストレージにアクセスする必要があります。これらは、サードパーティ Cookie が非推奨になり、ストレージ パーティショニングが有効になった後は利用できなくなります。

次のようなユースケースがあります。

  • ログイン セッションの詳細情報を必要とする埋め込みコメント ウィジェット。
  • ログイン セッションの詳細を要求するソーシャル メディアの「いいね」ボタン。
  • ログイン セッションの詳細情報を必要とする埋め込みドキュメント。
  • 埋め込み動画の高度な機能(たとえば、ログイン ユーザーには広告を表示しない、字幕に関するユーザー設定を把握する、特定の動画タイプを制限するなど)。
  • 組み込みの支払いシステム。

これらのユースケースの多くには、埋め込み iframe でログイン アクセスを持続させることが含まれます。

他の API ではなく Storage Access API を使用する場合

Storage Access API は、パーティション分割されていない Cookie とストレージを使用する代替手段の 1 つであるため、この API を使用するタイミングを他の API と比較して理解することが重要です。次の両方に該当するユースケースを対象としています。

  • ユーザーは埋め込みコンテンツを操作します。つまり、パッシブ iframe や隠し iframe ではありません。
  • ユーザーがトップレベル コンテキストで埋め込まれたオリジンにアクセスした(そのオリジンが別のサイトに埋め込まれていないとき)。

さまざまなユースケースに対応する代替 API が用意されています。

  • Cookies Having Independent Partitioned State(CHIPS)により、デベロッパーは、トップレベル サイトごとに個別の Cookie jar を使用して、Cookie を「パーティション分割」ストレージにオプトインできます。たとえば、サードパーティのウェブチャット ウィジェットは、セッション情報を保存するために Cookie の設定に依存することがあります。セッション情報はサイトごとに保存されるため、ウィジェットで設定された Cookie が埋め込まれている他のウェブサイトからアクセスする必要はありません。Storage Access API は、埋め込まれたサードパーティ製ウィジェットが、異なるオリジンで同じ情報(ログイン セッションの詳細や設定など)を共有することに依存している場合に役立ちます。
  • ストレージ パーティショニングは、クロスサイト iframe で既存の JavaScript ストレージ メカニズムを使用し、基盤となるストレージをサイトごとに分割する方法です。これにより、あるウェブサイトの埋め込みストレージが、他のウェブサイトにある同じ埋め込みストレージからアクセスされるのを防ぐことができます。
  • 関連ウェブサイト セット(RWS)は、組織がサイト間の関係を宣言するための方法です。これにより、ブラウザは特定の目的のために、パーティション分割されていない Cookie やストレージへのアクセスを制限できます。サイトは引き続き Storage Access API を使用してアクセスをリクエストする必要がありますが、セット内のサイトについては、ユーザーのプロンプトなしでアクセス権を付与できます。
  • Federated Credential Management(FedCM)は、フェデレーション ID サービスのプライバシー保護アプローチです。Storage Access API は、パーティション分割されていない Cookie へのアクセスとログイン後のストレージに対応します。ユースケースによっては、Storage Access API に代わるソリューションとして FedCM が提供されています。FedCM はログイン指向のブラウザ プロンプトを備えているため、望ましい場合があります。ただし、FedCM を導入するには、通常、コードに追加の変更(HTTP エンドポイントのサポートなど)が必要になります。
  • 不正防止 API、広告関連 API測定 API もありますが、Storage Access API はこれらの懸念に対処することを意図したものではありません。

Storage Access API の使用

Storage Access API には、Promise ベースのメソッドが 2 つあります。

Permissions 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 via 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 内の同一オリジンのナビゲーション全体で保持されます。これは、HTML ドキュメントに対する最初のリクエストに Cookie の存在が必要なページへのアクセスを許可した後でも再読み込みできるようにするためです。

requestStorageAccess() メソッドの使用

iframe にアクセス権がない場合は、requestStorageAccess() メソッドを使用してアクセス権をリクエストする必要があります。

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

これが初めてリクエストされたときに、ユーザーはブラウザ プロンプトでこのアクセスを承認する必要がある場合があります。その後 Promise が解決されるか、await が使用されている場合は拒否されて例外が発生します。

不正行為を防止するため、このブラウザのプロンプトはユーザーの操作後にのみ表示されます。そのため、iframe の読み込み直後ではなく、ユーザーが開始したイベント ハンドラから requestStorageAccess() を最初に呼び出す必要があります。

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 above 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 のメッセージの例ですが、他のブラウザでも同様の UI があります。

Chrome Storage Access API の権限プロンプトのスクリーンショット
Chrome の Storage Access API 権限プロンプト

次のような特定の状況では、ブラウザでプロンプトがスキップされ、権限が自動的に提供されることがあります。

  • メッセージを受け入れてから過去 30 日間にページと iframe が使用されているかどうか。
  • 埋め込み iframe が関連ウェブサイト セットの一部である場合。
  • Firefox では、既知のウェブサイト(トップレベルで操作したことのあるウェブサイト)についても最初の 5 回までプロンプトはスキップされます。

また、特定の状況では、プロンプトを表示せずにメソッドが自動的に拒否されることがあります。

  • iframe 内ではなく、トップレベルのドキュメントとして iframe を所有しているサイトにユーザーがアクセスしたことがなく、操作したことがない場合。つまり、Storage Access API は、ユーザーが以前にファーストパーティのコンテキストでアクセスした埋め込みサイトにのみ有用です。
  • 操作後のプロンプトに対する事前の承認なしに、ユーザー操作イベントの外部で requestStorageAccess() メソッドが呼び出された場合。

初回の使用時にはメッセージが表示されますが、2 回目以降のアクセスでは、Chrome や Firefox でユーザーが操作しなくても requestStorageAccess() を解決できます。Safari では常にユーザーの操作が必要です。

Cookie とストレージへのアクセス権は、プロンプトやユーザーの操作なしで付与される場合があるため、多くの場合、ページ読み込み時に requestStorageAccess() を呼び出すことで、この機能をサポートしているブラウザ(Chrome と Firefox)でユーザーが操作を行う前に、パーティション分割されていない Cookie またはストレージへのアクセス権を取得できます。これにより、ユーザーが iframe を操作する前でも、パーティション分割されていない Cookie やストレージにすぐにアクセスして、完全なエクスペリエンスを提供できます。これにより、状況によっては、ユーザーの操作を待つよりもユーザー エクスペリエンスが向上することがあります。

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 older 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') {
            // Currently not used. See:
      // https://github.com/privacycg/storage-access/issues/149
      return false;
          }
    }

  // By default return false, though should really be caught by one of above.
  return false;
}

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

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

handleCookieAccessInit();

サンドボックス化された iframe

サンドボックス化された iframe で Storage Access API を使用する場合は、次のサンドボックスの権限が必要です。

  • Storage Access API へのアクセスを許可するには、allow-storage-access-by-user-activation が必要です。
  • JavaScript を使用して API を呼び出すには、allow-scripts が必要です。
  • 同一生成元の Cookie やその他のストレージへのアクセスを許可するには、allow-same-origin が必要です。

次に例を示します。

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

Chrome で Storage Access API を使用してアクセスするには、次の 2 つの属性でクロスサイト Cookie を設定する必要があります。

  • SameSite=None - Cookie をクロスサイトとしてマークするために必要です。
  • Secure - HTTPS サイトによって設定された Cookie にのみアクセスできます。

Firefox と Safari では、Cookie はデフォルトで SameSite=None に設定され、SSA が Secure Cookie に制限されないため、これらの属性は必要ありません。SameSite 属性を明示的に指定し、常に Secure Cookie を使用することをおすすめします。

トップレベルのページへのアクセス

Storage Access API は、埋め込み iframe 内でサードパーティ Cookie にアクセスできるようにするためのものです。

他にも、トップレベル ページでサードパーティ Cookie へのアクセスが必要なユースケースがあります。たとえば、Cookie によって制限されている画像やスクリプトを iframe ではなく最上位のドキュメントに直接含めたいサイト所有者がいるとします。このユースケースに対応するために、Chrome は requestStorageAccessFor() メソッドを追加する Storage Access API の拡張機能を提案しています。

requestStorageAccessFor() メソッド

対応ブラウザ

  • 119
  • 119
  • x
  • x

ソース

requestStorageAccessFor() メソッドは requestStorageAccess() と同じように動作しますが、最上位のリソースを対象とします。サードパーティ Cookie への一般的なアクセス権の付与を防ぐために、関連ウェブサイト セット内のサイトでのみ使用できます。

requestStorageAccessFor() の使用方法について詳しくは、関連ウェブサイト セット: デベロッパー ガイドをご覧ください。

top-level-storage-access 権限のクエリ

対応ブラウザ

  • x
  • x
  • x
  • x

storage-access 権限と同様に、requestStorageAccessFor() にアクセス権を付与できるかどうかを確認する top-level-storage-access 権限があります。

RWS で使用する場合の Storage Access API の違い

関連ウェブサイト セットを Storage Access API で使用する場合、次の表で示すような追加機能を利用できます。

RWS なし RWS 搭載
ストレージ アクセスのリクエストを開始するにはユーザー操作が必要です
アクセス権を付与する前に、最上位のコンテキストでリクエストされたストレージ オリジンにアクセスする必要がある
初回ユーザー メッセージはスキップ可能
アクセス権がすでに付与されている場合は requestStorageAccess を呼び出す必要はありません。
関連ウェブサイト サイトの他のドメインのアクセス権を自動的に付与します
最上位レベルのページへのアクセスをrequestStorageAccessFor サポートします
Storage Access API を使用する場合、関連ウェブサイト セットを使用する場合と使用しない場合の違い

デモ: Cookie の設定とアクセス

次のデモは、デモの最初の画面で設定した Cookie に、デモの 2 番目のサイトの埋め込みフレームでアクセスする方法を示しています。

storage-access-api-demo.glitch.me

このデモでは、サードパーティ Cookie を無効にしたブラウザが必要です。

  • chrome://flags/#test-third-party-cookie-phaseout フラグを設定し、ブラウザを再起動した Chrome 118 以降。
  • Firefox
  • Safari

デモ: ローカル ストレージの設定

次のデモは、Storage Access API を使用して、サードパーティの iframe からパーティション分割されていないブロードキャスト チャンネルにアクセスする方法を示しています。

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

このデモを行うには、test-third-party-cookie-phaseout フラグを有効にした Chrome 125 以降が必要です。

リソース