October 1, 2020
CSS Tricks # CSSを利用して視覚的な変化を起こすことで、ユーザーが埋め込みピクセル値などの情報を暴露するように騙すことができます。
ユーザのヒストリーを取得する # CSSの:visitedセレクタを使うと、訪問したことのある URL に対して異なるスタイルを適用することができます。 以前はgetComputedStyle()を使ってこの違いを検出することができましたが、昨今のブラウザでは常にリンクが訪問されたかのような値を返すことでこれを防ぎ、セレクタを使って適用できるスタイルを制限しています。1
そこで、CSSが効いた領域をクリックするようにユーザーを誘導する必要があるかもしれませんが、これはmix-blend-modeを使って行うことができます。2 また、レンダリングタイミングを悪用することで、ユーザーとのインタラクションなしに、リンクを別の色に塗り替える方法もあります。3 複数のリンクを使用して時間差を増加させることで動作するPoCがchromium report上で提供されました。3
info
この攻撃例[^leak-1]は、もぐらたたきゲームを利用してユーザーをだましてページをクリックさせるものです。この問題に関して複数のブラウザにバグが報告されています。: ^bug-1, ^bug-2, ^bug-3 Captchaの悪用 # CSSを使えば、埋め込みをコンテキストから外部に取り出せます。 この例として、4に見られるようなcaptchaのふりをすることが挙げられます。 これは、埋め込み部分の幅と高さを設定することで、狙った文字だけが表示されるようにするものです。 複数の埋め込みを利用して、表示される文字の順番を変えて、何の情報を提供しているのかをユーザーが分かりづらくすることも可能です。
オートコンプリートの悪用 # テキスト入力を使用するウェブサイトで、autocomplete="off"を使用してオートコンプリートを無効にしない場合、電子メールアドレスなどのデータをリークできる場合があります。javascriptを使用したテキスト入力のオートコンプリート機能を利用するために、ユーザーを騙して、キーを押させることができます。 Chromeの場合、上または下矢印キーを押してダイアログを開き、値を選択した後、EnterキーまたはTabキーを押して値をページに挿入するようにユーザーを誘導することが必要です。
let input = document.createElement("input"); input.type = "email"; input.autocomplete = "email"; input.name = "email"; input.size = "1"; input.style = "position:absolute;right:-500px;bottom:-21.9px"; input.onkeypress = e => { e.preventDefault(); } window.onmousedown = e => { // マウスのクリックを無視する e.preventDefault(); } input.onchange = e => { alert(e.
...
October 1, 2020
ウィンドウの参照により、クロスオリジンのページが他のページのいくつかの属性にアクセスできます。 これらの参照は、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); 事例 # フレームカウント攻撃の例としては、以下のようなものがあります。
...
October 1, 2020
クロスサイトのページで画面遷移がトリガーされたか(または、そうでないか)を検出することは攻撃者にとって有用です。例えば、ウェブサイトはユーザの状態に依存(#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.
...
October 1, 2020
ネットワーク タイミングのサイドチャネルは、ウェブが誕生したときから存在していました。これらの攻撃は、ブラウザが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.
...
October 1, 2020
ブラウザ上での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.
...
October 1, 2020
id属性はHTML要素を識別するために広く利用されています。残念ながらクロスオリジンのウェブサイトでfocusイベントとURLフラグメントを利用することによって、ページのどこにid属性が与えられているかを決定することができます。例えば、https://example.com/foo#barが読み込まれると、ブラウザはid="bar"が与えられた要素までスクロールしようとします。これはクロスオリジンのサイトで定義したiframeでhttps://example.com/foo#barを読み込むことによって検出することができます。もし、 id="bar" を持つ要素がある場合は、 focus イベントが発生します。 focus イベントもまた同じ目的で使用することができます1。
いくつかのウェブアプリケーションはfocusable要素にid属性を設定しており、ユーザ情報の開示につながります。これらのid属性には、ユーザに直接関連する機密情報やユーザの状態(アカウントの状態)に関連する情報を含めることができます。
コード # 以下のコードは別のサイトからID属性を検出する例を示しています:
// onblurイベントをリッスン onblur = () => { alert('Focus was lost, so there is a focusable element with the specified ID'); } var ifr = document.createElement('iframe'); // ページに id="x" のフォーカス可能な要素がある場合、フォーカスを得ることができます。 // 例: <input id="x" value="test" /> ifr.src = 'https://example.org/#x'; document.body.appendChild(ifr); info
上記の手法はFireFoxではうまく動作しない可能性があります。 攻撃シナリオ # id属性を利用した攻撃は以下のような物があります。
とある銀行がモバイルデバイスのセッションを認証するために短い数字のワンタイムPin(OTP)を生成することを許可しています。この銀行のページはクライアントにPINコードを表示するためのbutton要素のidにOTPコードそのものを使用していました。この挙動を悪用し、すべてのオプションをブルートフォースすることでOTPコードを窃取し、ユーザアカウントを侵害することができます。 とあるウェブアプリケーションが、プレミアムアカウントのステータスを持つユーザや、特定の性別のユーザである場合、あらかじめ定義されたidとHTML要素の組み合わせを利用します。攻撃者は、被害者のページに特定のidがあるかを検出し、被害者のアカウント情報を漏えいさせることができます。 対策 # Document Policies SameSite Cookies (Lax) COOP Framing Protections Isolation Policies ✔️ ✔️ ✔️ ❌ FIP 参考文献 # Leaking IDs using focus, link ↩︎