COOP

Window References

October 8, 2020
Abuse Window References
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP

もしページが opener プロパティを null に設定したり、ユーザーの状態に応じて COOP による保護を使用している場合、その状態に関するクロスサイト情報を推測することができます。 例えば、攻撃者は認証されたユーザーのみがアクセスできる iframe (または新しいウィンドウ) でエンドポイントを開き、そのウィンドウの参照をチェックするだけで、ユーザーがログインしているかどうかを検出することができます。 コード # 以下のコードは、open プロパティが null に設定されているかどうか、あるいは COOP ヘッダーが unsafe-none 以外の値で存在するかどうかを検出する方法を示しています。 これは、iframeと新しいウィンドウの両方で行うことができます。 // 脆弱な攻撃対象URL const v_url = 'https://example.org/profile'; const exploit = (url, new_window) => { let win; if(new_window){ // 新しいタブを開き、win.opener が COOP の影響を受けたか、あるいは null に設定されたかどうかを確認 win = open(url); }else{ // opener が定義されているかどうかを検出するために iframe を作成 // COOP の検出や、ページがフレーム保護を実装している場合は機能しない document.body.insertAdjacentHTML('beforeend', '<iframe name="xsleaks">'); // iframeを脆弱な攻撃対象URLにリダイレクトする win = open(url, "xsleaks"); } // ページのロードを2秒待つ setTimeout(() => { // 新しく開いたウィンドウのオープナープロパティを確認する if(! ...

Frame Counting

October 1, 2020
Abuse iframes
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP, Framing Protections

ウィンドウの参照により、クロスオリジンのページが他のページのいくつかの属性にアクセスできます。 これらの参照は、iframeとwindow.openを使用または許可するときに利用可能となります。 この参照は、同一生成元ポリシーを尊重し続けるため、ウィンドウに関する(限定的な)情報を提供します。 アクセス可能な属性の1つは、ウィンドウ内のフレーム数を提供するwindow.lengthです。 この属性は、ページに関する貴重な情報を攻撃者に提供します。 Webサイトでは一般的にフレーム(またはiframes)を使用しますが、この選択は必ずしもセキュリティ上の問題を意味するわけではありません。 しかし、Webサイトがユーザの情報に応じてページのフレーム数を変更する場合があります。 例えば、GETパラメータと利用者のデータに応じてレイアウトを変えるようなページで起こりえます。 攻撃者は、異なるページで window.length の値を測定することにより、被害者に関する情報を推測することが可能かもしれません。 コード # 以下のコードは、クロスサイトのページにおけるフレーム数に関する情報にアクセスする方法を示しています。 // ウィンドウへの参照を取得する var win = window.open('https://example.org'); // ページが読み込まれるのを待つ setTimeout(() => { // 読み込まれたiframeの数を読み取る console.log("%d iframes detected", win.length); }, 2000); 攻撃の対策 # 場合によっては、異なるアプリケーション状態が同じ数のフレームを持つことで、攻撃者がそれらを区別できないようにすることができます。 ただし、ページの読み込み中にフレーム数を連続的に記録することで、攻撃者に情報をリークする可能性があるパターンを示す可能性もあります。 // ウィンドウへの参照を取得する var win = window.open("https://example.org"); var pattern = []; // ループ内で、60ms間隔でiframeの数を登録する var recorder = setInterval(() => { pattern.push(win.length) }, 60); // 6秒後にループを解除する setTimeout(() => { clearInterval(recorder); console.log("The pattern is: %s", pattern.join(', ')); }, 6 * 1000); 事例 # フレームカウント攻撃の例としては、以下のようなものがあります。 ...

Navigations

October 1, 2020
Abuse Downloads, History, CSP Violations, Redirects, window.open, window.stop, iframes
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP, Framing Protections

クロスサイトのページで画面遷移がトリガーされたか(または、そうでないか)を検出することは攻撃者にとって有用です。例えば、ウェブサイトはユーザの状態に依存(#case-scenarios)して、あるエンドポイントで画面遷移をトリガーする可能性があります。 どのような画面遷移が発生したかを検出することで攻撃者以下の様なことが可能になります。 iframeを使用してonloadイベントがトリガーされた回数を数える。 ウィンドウへの参照を通じてアクセス可能なhistory.lengthの値をチェックする。この値は被害者のhistory.pushStateや通常の画面遷移によって変更された履歴の数を提供しています。攻撃者はhistory.lengthの値を取得するためにウィンドウへの参照のlocationをターゲットのウェブサイトに変更し、そしてSame-Originに戻すことによって最後に値を読み取ります。 ダウンロードトリガー # エンドポイントがContent-Disposition: attachment ヘッダを設定すると、ブラウザにレスポンスをナビゲートさせるのではなくファイルとしてダウンロードすることを指示します。この挙動が発生したかを検出すると、結果が被害者の状態に依存する場合に攻撃者に機密情報をリークできる可能性があります。 ダウンロードバー # Chromeベースのブラウザではファイルをダウンロードする際に、ブラウザのウィンドウ下部にダウンロードの進捗を示すバーがウィンドウと一体化して表示されます。攻撃者ウィンドウの高さを監視することでダウンロードバーが開いているかどうかを検出することができます。 // ウィンドウの現在の高さを読み取る var screenHeight = window.innerHeight; // ダウンロードのトリガーとなるページを読み込む window.open('https://example.org'); // タブの読み込みを待つ setTimeout(() => { // ダウンロードバーが表示された場合、すべてのタブの高さが小さくなります if (window.innerHeight < screenHeight) { console.log('Download bar detected'); } else { console.log('Download bar not detected'); } }, 2000); important この攻撃は、自動ダウンロード機能が有効になっているChromeベースのブラウザでのみ有効です。加えてこの攻撃はユーザがダウンロードばーばを能動的に閉じないと再検出できないため、繰り返し行うことはできません。 iframeを利用したダウンロード遷移 # Content-Disposition: attachment ヘッダをテストするもう一つの方法は遷移が発生したかどうかをチェックすることです。仮にページの読み込みによってダウンロードが発生した場合、遷移は発生せずウィンドウは同一オリジン内に留まります。 以下のコードは、そのような遷移が発生したかを検出しダウンロードが試行されたかを検出します。 // ダウンロード試行時のテスト先URLを設定する var url = 'https://example.org/'; // onloadイベントを計測するための外側のiframeを作成する var iframe = document.createElement('iframe'); document.body.appendChild(iframe); // ダウンロードの試行をテストするために、内側のiframeを作成 iframe.srcdoc = `<iframe src="${url}" ></iframe>`; iframe. ...

Network Timing

October 1, 2020
Abuse iframes
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP, Framing Protections

ネットワーク タイミングのサイドチャネルは、ウェブが誕生したときから存在していました。これらの攻撃は、ブラウザがperformance.now()のような高精度のタイマーを出荷し始めたときに、新しい注目を集め、時とともに異なるレベルの影響を持つようになりました。 タイミング測定値を得るために、攻撃者は暗黙的または明示的なクロックを使用する必要があります。これらのクロックは、XS-Leaksの目的では通常交換可能であり、精度と利用可能性が異なるだけです。簡単のために、この記事では、すべてのモダンブラウザに存在する明示的なクロックであるperformance.now()APIを使用することを想定しています。 このサイドチャネルにより、攻撃者はクロスサイトリクエストが完了するまでにかかった時間から情報を推測することができます。ネットワークのタイミング測定は、ユーザーの状態によって変化する可能性があり、通常は下記の要素に連動します。 リソースサイズ バックエンドでの計算時間 サブリソースの数とサイズ キャッシュの状態. tip クロックの種類については、クロックの記事で詳しく説明しています。 モダンなWebのタイミング攻撃 # performance.now()は、リクエストの実行にかかる時間を測定するために使用できます。 // クロックを開始します。 var start = performance.now() // fetchリクエストが完了するまでの時間を計測します。 fetch('https://example.org', { mode: 'no-cors', credentials: 'include' }).then(() => { // fetch終了した時点で時間差を計算します。 var time = performance.now() - start; console.log("The request took %d ms.", time); }); Onloadイベント # 同じような処理で、リソースを取得するのにかかる時間を測定するには、単に onload イベントを監視することで可能です。 // 時間が欲しいページを指すscript要素を作成します。 var script = document.createElement('script'); script.src = "https://example.org"; document.body.appendChild(script); // クロックを開始します。 var start = performance.now(); // スクリプトがロードされたら、リクエストが完了するまでの時間を計算します。 script.onload = () => { var time = performance. ...

Execution Timing

October 1, 2020
Abuse Event Loop, Service Workers, Site Isolation, CSS Injections, Regex Injections, iframes
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP, Framing Protections

ブラウザ上でのJavaScriptの実行時間を測定することで、攻撃者は特定のイベントがいつ発生したか、ある操作にどれくらいの時間がかかったかといった情報を得ることができます。 イベントループのタイミング # JavaScriptの並行処理モデルは、single-threaded event loopに基づいており、これは一度に一つのタスクしか実行できないことを意味します。 例えば、ある時間のかかるタスクがイベントループをブロックした場合、UIスレッドが枯渇した結果として、ユーザーはページがフリーズしたように感じることがあります。 他のタスクはブロックされたタスクが終了するまで待たなければなりません。 各ブラウザは異なるプロセスモデルを実装しているので、ウェブサイトによっては、その関係によって異なるスレッド(およびイベントループ)で実行されることがあります。 このモデルを悪用して、クロスオリジンページから秘密を盗みだす手法があります。 イベントプールで次に実行されるまでの時間を測定することで、異なるオリジンのコードが実行されるまでの時間を推測する。攻撃者は固定されたプロパティを持つイベントをイベントループ12に送り続け、プールが空になると最終的にディスパッチされます。他のオリジンは同じプールにイベントをディスパッチし、ここで攻撃者はそのタスクの一つで遅延が発生したかどうかを検出することで、時間差を推測します。 攻撃者が制御する文字列によって前記の機密情報が比較される場合、クロスオリジンページから機密情報を盗む。このリークは、1文字ずつの文字列比較2のイベントループで時間差を比較した結果です(前出の手法を使用)。process isolationを行わないブラウザでは、異なるオリジン間のクロスウィンドウ通信が同じスレッドで実行され、同じイベントループを共有します。 important process isolationの仕組みがあるブラウザでは、後者の攻撃の可能性はすでにありません。このような仕組みは、現在Chromiumベースのブラウザでは Site Isolationのみで、Firefox にはProject Fission という名前で間もなく導入される予定です。 Busy Event Loop # 別の手法として、スレッドのイベントループをブロックし、イベントループが再び利用可能になるまでの時間を計測する方法があります。 この手法の主な利点の1つは、攻撃者のオリジンが他のオリジンの実行に影響を与えることができるため、Site Isolationを回避できることです。この攻撃は次のように動作します。 対象のウェブサイトをwindow.openで別ウィンドウに表示するか、iframe内に表示する。(Framing Protectionsが設定されていない場合) 長い計算が始まるのを待つ。 Framing Protectionsに関係なく、同じサイトのページをiframe内に読み込む 攻撃者は、(手順3の)iframeがonloadイベントをトリガーするのにかかった時間を計ることで、ターゲットのウェブサイトが実行された時間を検出できます。(Network Timing of step 3 should be minimal) 両方のナビゲーションは同じコンテキストで発生し、それらは同じサイトであるため、同じスレッドで実行され、同じイベントループを共有します。(それらは互いにブロックすることができます。) // 新しいウィンドウを開いて、example.comのイベントループを // ウィンドウがブロックする時間を測定する window.open('https://example.org/expensive'); // TODO: タイムアウトなどでコストの掛かるウィンドウがロードされるのを待ちます。 var ifr = document.createElement('iframe'); ifr.src = "https://example.org"; document.body.appendChild(ifr); // 初期時間の測定 var start = performance.now(); ifr.onload = () => { // iframeが読み込まれたら、時間差を計算する var time = performance. ...

Hybrid Timing

October 1, 2020
Abuse iframes
Category Attack
Defenses Fetch Metadata, SameSite Cookies, COOP

ハイブリッド・タイミング攻撃では、攻撃者は最終的なタイミング測定に影響を与える一連の要素の合計を測定することができます。これらの要素には以下のものがあります。 ネットワークの遅延 ドキュメントのパース サブリソースの検索と処理 コード実行 アプリケーションによって値が異なる要素もあります。つまり、Network Timing はバックエンドの処理が多いページでより重要かもしれませんし、一方 Execution Timing はブラウザ内でデータを処理し表示するアプリケーションでより重要かもしれないのです。攻撃者は、より正確な測定値を得るために、これらの要因のいくつかを排除することも可能です。例えば、攻撃者はページを iframe として埋め込むことによってすべてのサブリソースを事前にロードし(ブラウザにサブリソースをキャッシュさせる)、その後、それらのサブリソースの取得によって生じる遅延を除外した2度目の計測を行えます。 Frameタイミング攻撃(Hybrid) # ページがFraming Protectionsを設定していない場合、攻撃者はすべての要素を考慮したハイブリッドな計測結果を取得できます。この攻撃はNetwork-based Attackと似ていますが、リソースが取得されると、ブラウザによってページがレンダリングされて実行されます(サブリソースの取得と JavaScript の実行が行われる)。このシナリオでは、onloadイベントは(サブリソースとスクリプトの実行を含めて)ページが完全にロードされたときだけトリガーされます。 var iframe = document.createElement('iframe'); // 配送先のWebサイトのURLを設定する iframe.src = "https://example.org"; document.body.appendChild(iframe); // リクエストが初期化されるまでの時間を計測する var start = performance.now(); iframe.onload = () => { // iframeが読み込まれたら、時間差を計算する var time = performance.now() - start; console.log("The iframe and subresources took %d ms to load.", time) } 対策 # Attack Alternative SameSite Cookies (Lax) COOP Framing Protections Isolation Policies Frame Timing (Hybrid) ✔️ ❌ ✔️ FIP