Cache Probing
Cache Probingは、あるリソースがブラウザによってキャッシュされているかどうかを検知する手法です。そのコンセプトは、初期のWeb1から知られており、当初はタイミングの差異を検知することに基づいていました。 ユーザがWebサイトに訪れると、画像、スクリプト、そしてHTMLコンテンツなどの様々なリソースが取得され、それらは(特定の条件下で)ブラウザによってキャッシュされます。この最適化により、ブラウザはこれらのリソースを再度要求することなくディスクから提供するため、その後のナビゲーションが高速化されます。もし攻撃者がどのリソースがキャッシュされているかを検知できれば、この情報を基に、ユーザが特定のページにアクセスしたことがあるかどうかをリークできます。 Cache Probingのバリエーションとして、Error Eventsを悪用することにより、より正確でインパクトのある攻撃を実行することができます。 攻撃の原理 # 攻撃者は、あるユーザーがあるSNSを訪問したかどうかを知りたいと考えています。 そのSNSにアクセスすると、いくつかのサブリソースがキャッシュされます。 ユーザが、SNSが通常取得するリソースを取得する攻撃者のページを訪問する。 Network Timing XS-Leakの手法を用いて、攻撃者のページはキャッシュからの応答(つまりステップ1が起こった)とネットワークからの応答(つまりステップ1が起こらなかった)の違いを検出することができます。(応答がキャッシュからの場合、遅延は顕著に短くなります。) Error EventsによるCache Probing # Error Events2を利用したキャッシュプロービングは、より正確な攻撃を可能にします。このアプローチでは、時間の計測に頼らず、Error Eventsといくつかのサーバサイドの挙動を活用して、あるリソースがキャッシュされたかどうかを検出します。この攻撃は、以下のステップを必要とします。 ブラウザキャッシュからのリソースを無効化する。このステップは、攻撃が別の訪問で以前にキャッシュされたリソースを考慮しないことを確認するために必要です。 ユーザーの状態によって異なる項目がキャッシュされるようなリクエストを実行する。例えば、ユーザーがログインしている場合にのみ、特定の画像を含むページをロードする。このリクエストは、<link rel=prerender...で対象のウェブサイトに移動したり、iframeでウェブサイトを埋め込んだり、window.openで新しいウィンドウを開くことで発生させることができる。 サーバが拒否するようなリクエストを引き起こす。例えば、長大なRefererヘッダを含んでいて、サーバーがリクエストを拒否するような場合です。もし、ステップ2でリソースがキャッシュされていれば、このリクエストはエラーイベントを発生させることなく、成功します。 キャッシュの無効化 # キャッシュからのリソースを無効にするには、攻撃者はそのサブリソースを取得する際にサーバーがエラーを返すようにする必要があります。これを実現するには、いくつかの方法があります。 ブラウザによってリクエストが開始され、新しいコンテンツを受け取る前にAbortController.abort()で中止された cache:'reload'オプション付きのフェッチリクエスト 長大なRefererヘッダと 'cache':'reload'を持つリクエスト。ブラウザはこれを防ぐためにリファラの長さに上限を設けているので、これはうまくいかないかもしれません。 POSTリクエストに fetch no-cors を指定した場合。エラーが返されない場合でも、ブラウザがキャッシュを無効化することがあります。 Content-Type、Accept、Accept-Languageなど、サーバーを失敗させる可能性のあるリクエストヘッダ。(よりアプリケーションに依存します) その他のリクエストプロパティ これらの方法のいくつかは、しばしばブラウザのバグとみなされていそうです。(例: this bug). Origin ReflectionによるCORS error # Origin Reflectionは、グローバルにアクセス可能なリソースに、リクエストを初期化したオリジンを反映したAccess-Control-Allow-Origin(ACAO)ヘッダを付与する挙動のことです。これは、CORSの設定ミス3と考えることができ、ブラウザのキャッシュにリソースが存在するかどうかを検知するのに使用できます。 info 例えば、Flask frameworkにおいて、origin refrectionはデフォルトの動作になっています。 もし server.com にホストされているリソースが target.com からリクエストされた場合、オリジンはレスポンスヘッダに次のように反映されるでしょう。Access-Control-Allow-Origin: target.com といった具合です。リソースがキャッシュされている場合、この情報はリソースと一緒にブラウザのキャッシュに保存されます。これにより、もし attacker.com が同じリソースを取得しようとした場合、2つの可能性があります。 リソースがキャッシュにない場合:リソースは Access-Control-Allow-Origin: attacker.com ヘッダーとともにフェッチされ、保存される可能性があります。 リソースがすでにキャッシュにある:フェッチ試行はキャッシュからリソースをフェッチしようとするが、要求しているオリジンと ACAO ヘッダーの値の不一致によりCORSエラーが起こる。(target.comが期待されているが、実際に提供されたのはattacker.com 。)以下に、この脆弱性を悪用して被害者のブラウザのキャッシュ状態を推測するコード例を示します。 // この関数は、単にURLを受け取り、CORS モードでfetchします。 // fetchでエラーが発生した場合、attacker. ...