はじめに
こんにちは。フューチャーの棚井龍之介と申します。認証認可連載の 4 本目を担当しました。
認証認可周りは最近触りたてでして、普段の開発業務では、Go・React・AWS を利用しています。
先日、React ベースのモバイル向け Web アプリに Auth0 の認証を実装したところ、Silent Authentication(サイレント認証)のタイミングでブラウザからトークンが消失し、ログイン状態が維持できない現象に遭遇しました。
調べたところ、Safari に搭載されているトラッキング防止機能の ITP(Intelligent Tracking Prevention / インテリジェント・トラッキング・プリベンション)が原因だと判明しました。
調べる過程で、Cookie の基本的な機能からアドテク周りの技術要素、最近のプライバシー保護トレンドについて触れる機会を得ましたので、技術ブログとして整理しました。
本記事では、以下の内容を扱います
- Cookie(1st Party、3rd Party)
- ITP(Intelligent Tracking Prevention)
- ITP による、Auth0 の PKCE フローへの影響
- 対応方法
前半は Cookie とプライバシー保護の話で、後半が Auth0 と ITP の話です。
Cookie とは
Cookie とは、Web サイトに訪れたユーザの情報を、一時的に保存する機能のことです。
この「一時保存する機能」により、ユーザのログイン状態を維持することや、Web ページに再訪したときに「この人は、以前にウチのサイトに来た〇〇さんだ!」と判定できます。
「以前に来た〇〇さん」と技術的に判定できると、次は「きっと〇〇さんならば…」という「Cookie により収集された個人属性の、Web 広告利用」へと直結させる動きが当然出てきます。
最近だとプライバシー保護の観点から、こういった Web 広告の規制が強化されるトレンドにあります。例えば、Web サイトのトップページに訪問した際に「Cookie の有効化に同意してください。Yes or No」がポップアップで表示されて、オプトインでの意思表示が求められるのは、このトレンドに乗ったものだと思います。
Cookie の分類
続いて、Cookie の分類を見ていきます。
Cookie の発行元が、訪問しているサイト(ドメイン)と同じか別かにより、1st Party Cookie と 3rd Party Cookie と呼び方が変わります。
Cookie の発行元と訪問しているサイト(ドメイン)の関係 | Cookie の呼び方 |
---|---|
同じ(Cookie の発行者は、訪問したサイトの運営者である) | 1st Party Cookie |
異なる(Cookie の発行者は、訪問しサイトとは別の外部の第三者である) | 3rd Party Cookie |
主に、外部のサービスを利用して「ユーザ行動に合わせた Web 広告を表示したい(ターゲティング広告を実施したい)」や「ログイン状態管理などの特定の機能を外部に任せたい」ケースで 3rd Party Cookie が利用されることが多いと思います。
ITP(Intelligent Tracking Prevention)とは
ひとこと言うと、ITP は「3rd Party Cookie の利用を禁止する技術」です。
先ほど、3rd Party Cookie により実現できることの 1 つに「ターゲティング広告(ユーザの行動履歴を元にした、Web 広告最適化)」があると述べました。ターゲティング広告により、各ユーザごとに個別最適化された(高いクリック率を獲得できる見込みの)Web 広告が表示できます。これにより、Web 広告のクリック率向上 → 購入率の向上が見込まれます。アドテク技術の進歩により、この Web 広告の精度が高まるほど、広告掲載ページ・広告を載せたい企業・その仕組みを提供する企業などの「Web マーケティング」界隈にとっては嬉しい世界になります。
その一方で、プライバシー保護の観点から、以下のような考え方が広まりつつあります。
(1)Web 広告の精度が高まる
↓
(2) ユーザの趣味嗜好を高精度で特定できる
↓
(3) 高精度な趣味嗜好の情報って、それはもはや個人情報では?
↓
(4) 個人情報を無断でクロスドメインに共有するは、プライバシー保護観点から NG では?
(例えば、あるユーザ α の行動履歴を取得した A 社が、その情報を Web 広告機能を提供する B 社に「α の同意がない状況で」共有するケース)
このような考え方はメガテック企業でも意識され、Safari や Chrome などのブラウザによる規制も進んでいます。
例えば、Apple では 2017 年から Safari での 3rd Party Cookie の利用制限を段階的に導入しており、iOS14 ではついに Safari だけでなく Chrome・Firefox 含めて 3rd Party Cookie の利用が全面禁止になりました。
Google においても、Chrome での 3rd Party Cookie の利用を「2024 年後半に向けて段階的に廃止する可能性がある」と発表し、その代替技術として「プライバシー・サンドボックス」の開発・ユーザテストを進めています。ただ、Google は当初は 2022 年 1 月に規制を開始すると発表していましたが、その後に 2023 年後半に開始予定と延期し、さらに 2024 年後半と再延期しています。
Safari での ITP 規制状況を見ると、ユーザー情報のクロスサイトトラッキングを規制しようとする Apple と、規制の穴を探すアドテク企業の戦いが垣間見れます。
アップデート | リリース | 規制概要(*1) |
---|---|---|
ITP1.0 | 2017 年 9 月 | 特定の 3rd Party Cookie は 24 時間で削除 |
ITP2.0 | 2018 年 9 月 | 特定の 3rd Party Cookie は即時削除 |
ITP2.1 | 2019 年 3 月 | 特定の 1st Party Cookie は 7 日間で削除 |
ITP2.2 | 2019 年 4 月 | 特定の 1st Party Cookie は 24 時間で削除 |
ITP2.3 | 2019 年 9 月 | 特定の localstrage 上のデータを即時削除 |
iOS13.1 | 2020 年 3 月 | 全ての 3rd Party Cookie を即時削除 |
iOS14.0 | 2020 年 9 月 | iOS で稼働する Firefox, Chrome にも ITP を適用開始 |
(*1)より詳細な規制内容はこちらを参照お願いします。
3rd Party Cookie は何もアドテク領域に閉じた技術ではなく、それ以外の分野でも利用されています。
次は、ITP により Auth0 のトークンがうまく動かなくなってしまう話に移ります。
Auth0 のトークン取得フローと ITP ブロックへの対応
Auth0 の React 用 SDK(auth0-react)を利用する場合、PKCE(Proof Key for Code Exchange)の認証認可フローに従います。フローの詳細はこちらのサイトに記載があります。
Auth0 の JavaScript SDK ではログイン成功後、トークンを取得して、ブラウザのインメモリにキャッシュされます(上図での (9) で取得した Access Token をインメモリに保存する)。インメモリに保存すると、ページ遷移や画面リロードの度にトークンの再取得が必要で色々と面倒になりそうですが、この辺のトークンリフレッシュを Auth0 側では「Silent Authentication(サイレント認証)」により解決しています。サイレント認証により、ログイン状態を維持しながら、トークンをインメモリでセキュアに保持できます。
3rd Party Cookie が ITP で強制消去される
Auth0 x React でのログイン状態の管理が
(1)ID/Pass を入力してログインし、トークンを取得
(2)サイレント認証でトークンのリフレッシュ、ログイン状態を維持
(3)トークンの破棄、ログアウト
の 3 つで完結するならばこれで話は終わりですが、昨今の ITP(3rd Party Cookie の禁止)により、(2) のサイレント認証に失敗するケースが出てきました。
例えば、会社 Z が Auth0 でログイン機能を実装した Web サービスを運営しているとします。サービスの運営会社 Z と Auth0 では「異なるドメインの会社」になるため、Auth0 の発行したトークンが、Z 社の Web ページ上では 3rd Party Cookie と判定されて、ブラウザにより Cookie が強制消去されるケースが有り得る、ということです。サイレント認証に失敗すると「ログイン状態を維持できない(ページ遷移・リロードの度にログイン処理を求めることになる)」ため、ユーザ体験を大きく損なってしまいます。
ITP により 3rd Party Cookie が消去されたとき、Auth0 のコンソール画面、Safari の Web Inspector それぞれで以下の挙動が得られます。
↑
Auth0 のコンソール画面では「ログインには成功」しているが「サイレント認証には失敗」している
↑
Web Inspector のネットワークのログから、前述した PKCE フロー (3) の /authorize
は Call されているが、3rd Party Cookie がブラウザにより消去されているため、(7) の /oauth/token
が Call されない。→ PKCE フローが途中終了しているため、認証は「失敗」である。
ITP への対応方法
サイレント認証が ITP により失敗する問題には、Auth0 公式が 2 つの対応方法を提示しています。
(1)リフレッシュトークンローテーションを設定する
(2)カスタムドメインを設定する
この 2 つを設定すれば、ITP による 3rd Party Cookie 消失問題には対応できます。
また、ブラウザの設定変更で「ITP をオフにする」ことも可能なので、問題切り分け手法の 1 つとして覚えておくと、後々に役立つかも知れません。
以下は iPhone のブラウザ設定画面です。
スクショは ITP がオンの状態で撮影したものなので、Safari は「『サイト越えトラッキングを防ぐ』をオフ」にすることで、Chrome は「『Web サイト超えトラッキングを許可』をオン」にすることで、ITP を無効化できます。
以下はリフレッシュトークン・カスタムドメインのどちらも設定せずに、エミュレーターの Safari 設定で ITP をオフにした場合の挙動です。Auth0 のコンソール画面、Web Inspector のログから、/authorize
と/oauth/token
が Call されて、PKCE フローが正常終了してサイレント認証に成功していることが分かります。
おわりに
モバイル向けの Web ページを作成してリリースし、リリース後の動作チェックで「あれ、iOS だとログイン状態が維持できてない!?」と気づき、OAuth2.0 の仕様や PKCE の確認、インスペクタのログと認証フローと付き合わせながら、処理に失敗している場所の特定にまで至れました(1)「ITP」について知見がなかったこと、(2) 事前チェックが Android と Chrome シミュレーターだけで、iOS は工数削減のため未実施だったことが根原因なのですが、スマホと PC・iOS と Android で色々細かいところが違うのなー(なので、モバイル実機テストは Android と iOS は両方やろう)と再認識する機会になりました。