![3rd Party Cookieをトップレベルサイト毎に分割して保存するCHIPSを試してみた](https://images.ctfassets.net/ct0aopd36mqt/1dD7b8HkT2sbiJzUIewMTD/e5cdc6f33c4fdd9d798f11a4564612ff/eyecatch_developersio_darktone_1200x630.jpg)
3rd Party Cookieをトップレベルサイト毎に分割して保存するCHIPSを試してみた
西田@リテールアプリ共創部マッハチームです
今回は 3rd Party Cookie をトップレベルサイト毎に分割して保存するCHIPSを試してみました
CHIPSとは?
3rd Party Cookieをトップレベルサイト(埋め込まれる側のサイト、オリジン)毎に別々に分けて保存できるようにするCookieの仕様です
3rd Party Cookieが廃止されることを背景に、トラッキング用途以外のユースケースを満たせるように考えられました
ユースケース
埋め込まれたサイトのクッキーがトップレベルサイト毎に別々の値として保存されても問題ないようなケースで使えます
具体的な例をあげます。サイト埋め込み型のサポートチャットを提供してるSaaSがあるとします。このSaaSは他のサイトに埋め込まれる形で提供されます。
ショッピングサイトAでこのサービスを利用してサポートチャットを提供してるとします。また、別の動画配信サイトでも同様にこのサポートチャットサービスを利用してサポートチャットを提供してるとします
同じ、一人のユーザーがショッピングサイトと動画配信サイトでそれぞれチャットで問い合わせを行った場合に、それぞれのサイトのチャット履歴を関連づける必要はありませんが、それぞれのサイト毎の過去の履歴を保持できることは有益です
Cookieを保存するキー
CHIPSでない従来のCookieはオリジンのドメインをキーにして保存されています。 site.example
であれば (site.example)
がキーになります
CHIPSは、トップレベルサイトのドメインと埋め込まれた側(3rd Party)のドメインとの複合キーで保存されます。例えば site.example.com
に埋め込まれた embedded.example.com
のキーは (site.example.com, embedded.example.com)
になります
以下は embedded.example.com
が site.example.com
と other.example.com
でそれぞれ埋め込まれた際にキーがどのようになるのかを表した表です
トップレベル | 埋め込まれたサイト | キー |
---|---|---|
site.example.com | embedded.example.com | (site.example.com, embedded.example.com) |
other.example.com | embedded.example.com | (other.example.com, embedded.example.com) |
サブドメイン
パーティションキーはSame Siteの判定とおなじトップレベルサイトの eTLD + 1 の値が使われます。つまりSame Siteのトップレベルサイトに埋め込まれた Partitioned なCookieは同じクッキーになります
複数のサイトをサブドメインで展開してるサービスがあるとして、それぞれのサイトで同じクッキーになるので、サイトを跨いで同一のユーザーとしてサービスを提供できます
以下は埋め込み式のチャットサービスがあり、 cat.example
のサブドメインで複数サービスを提供してるサイトに埋め込まれており、 dog.example
サイトにも埋め込まれている例です
使用方法
Set-Cookie HTTPヘッダに Partitioned
属性をつけます
Set-Cookie: __Host-example=34d8g; SameSite=None; Secure; Path=/; Partitioned;
CHIPSはSecure属性をTrueにする必要があり、3rd Party Cookieとして取り扱うので、 SameSite=None;
もつけます
また、Cookieの名前にはオリジンのドメインしかアクセスされないよう __HOST Prefix をつけることが推奨されています
試してみた
トップレベルサイトと、そのサイトに埋め込まれるサイトをAWS上で構築し、実際にクッキーがどのように保存されるのかを試してみます
構成は以下でAPI GatewayとLambdaを使って構築しました
以下の二つのドメインが埋め込まれる側のトップレベルサイトのドメインです。この二つは eTLD+1の値が同じなので、同じ Cookie の値になるはずです
- topa.xxx.example (実際には
xxx.example
部分は筆者の取得したドメイン) - topb.xxx.example
以下は埋め込まれる側のドメインです。
- xxx.excute.api... (実際にはデフォルトで払い出される API Gatewayのドメインです)
埋め込まれる側のサイトのLambdaでは以下の処理をしています
- 送信されたCookieをパース
- Cookieが送信されなかった場合、ランダムな値を生成しSet-Cookieで
Partitioned
属性をつけてブラウザのCookieに設定します
const COOKIE_NAME = "__Host_id";
const parseCookie = (value: string): { [key: string]: string } => {
const cookie: { [key: string]: string } = {};
value.split(";").forEach((pair) => {
const [key, val] = pair.split("=");
cookie[key.trim()] = val;
});
return cookie;
};
const getRandomValue = (length: number): string => {
const randomValue = new Uint8Array(length);
getRandomValues(randomValue);
return Array.from(randomValue)
.map((v) => v.toString(36))
.join("");
};
export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
console.log(event.headers);
const cookies = parseCookie(event.headers?.Cookie || "");
let cookieValue = cookies[COOKIE_NAME];
if (cookieValue == null) {
cookieValue = getRandomValue(10);
}
return {
statusCode: 200,
headers: {
"Content-Type": "text/html",
"Set-Cookie": `${COOKIE_NAME}=${cookieValue}; SameSite=None; Secure; Partitioned`,
},
body: HTML,
};
}
片側(topa)のトップレベルドメインの確認
topa.xxx.example
のサイトにアクセスし開発者ツールでCookieの値を確認すると以下のことが確認できます
- 埋め込まれてる側のドメインがCookieのドメインとして設定されてる
- Partition Keyに eTLD + 1 の値
xxx.example
が設定されてる
もう片側(topb)のトップレベルドメインの確認
topa.xxx.example
のサイトにアクセスし開発者ツールでCookieの値を確認すると以下のことが確認できます
- 埋め込まれてる側のドメインがCookieのドメインとして設定されてる
- Partition Keyに eTLD + 1 の値
xxx.example
が設定されてる - Cookieの値が topa と同じ値になってる
別のドメイン
全く異なったドメインに、埋め込まれたサイトでも確認してみます。開発者ツールでCookieの値を確認すると、以下のことが確認できました
- 埋め込まれてる側のドメインがCookieのドメインとして設定されてる
- Parition Keyが異なるサイトのドメイン
- Cookieの値が topa, topb と異なっている
SafariではCHIPSは未対応
SafariではCHIPSは未対応なので Partitioned
属性をつけたCookieでも3rd Party Cookieはブラウザに保存されず、リクエストのHTTPヘッダにもCookieは含まれませんでした
最後に
今回は3rd Party Cookieをトップレベルサイト毎に分けて保存する CHIPS を試してみました。用途は限定的であるものの、3rd Party Cookie廃止後に用途によっては今までのCookieのユースケースを一部を満たせることがわかりました
この記事が誰かの参考になれば幸いです