一部のHTML要素は、クロスオリジンのページにデータの一部をリークさせるために使用される可能性があります。 たとえば、以下のようなメディアリソースは、サイズ、期間、種類に関する情報をリークさせる可能性があります。
HTMLMediaElementは、メディアのdurationとbufferedの時間をリークします。 HTMLVideoElement はvideoHeightとvideoWidthをリークします。一部のブラウザでは、webkitVideoDecodedByteCount、 webkitAudioDecodedByteCount、webkitDecodedFrameCountも含む可能性があります getVideoPlaybackQuality()はtotalVideoFramesをリークします。 [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement)はheightとwidthをリークしますが、画像が無効な場合には、それらは0となり、image.decode()は拒否されます。 メディアタイプの固有のプロパティによって、メディアタイプを区別することができます。 たとえば、<video>の場合はvideoWidth、<audio>の場合はdurationといった具合です。 以下のコードは、リソースの種類を返すサンプルコードを示しています。
async function getType(url) { // リソースがaudioもしくはvideoかどうかを検知 let media = document.createElement("video"); media.src = url; await new Promise(r=>setTimeout(r,50)); if (media.videoWidth) { return "video"; } else if (media.duration) { return "audio" } // リソースがimageかどうかを検知 let image = new Image(); image.src = url; await new Promise(r=>setTimeout(r,50)); if (image.width) return "image"; } CORBの悪用 # CORB は、間違ったコンテンツタイプが使用された場合にレスポンスを空にするChromeの機能です。 これは、コンテンツタイプが間違っている場合、キャッシュされないことを意味します。 ifCached 関数についてはCache Probingの記事にて確認できます。
async function isType(url, type = "script") { let error = false; // urlをパージする await ifCached(url, true); // リソースの読み込みを試行 let e = document.
...
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
ハイブリッド・タイミング攻撃では、攻撃者は最終的なタイミング測定に影響を与える一連の要素の合計を測定することができます。これらの要素には以下のものがあります。
ネットワークの遅延 ドキュメントのパース サブリソースの検索と処理 コード実行 アプリケーションによって値が異なる要素もあります。つまり、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
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 ↩︎
October 1, 2020
network timingを測定する方法の一つとして、ブラウザのソケットプールを悪用する方法があります。 ブラウザはサーバと通信するために、ソケットを利用します。 ハードウェアやその上で動作するOSのリソースには限りがあるため、ブラウザにも制限をかけざるを得ません。
この制限の存在を悪用するために、攻撃者は下記のようなことができます。
ブラウザの制限を確認する。 単に接続をハングアップさせる \(255\) のリクエストを別々のホストに実行して、長時間 \(255\) のソケットをブロックする。 ターゲットページに対するリクエストを実行して、 \(256^{番目}\) のソケットを利用する。 他のホストへの \(257^{番目}\) のリクエストを実行します。(step2、3で)すべてのソケットが使用されているので、このリクエストは、プールが利用可能なソケットを受け取るまで待機する必要があります。この待ち時間は、ターゲットページに属する \(256^{番目}\) のソケットのネットワークタイミングを、攻撃者に提供します。これが動作するのは、ステップ2の \(255\) 個のソケットがまだブロックされているので、ステップ3のソケットの解放によってプールが利用可能なソケットを受信した場合です。 \(256^{番目}\) のソケットを解放する時間は、リクエストを完了するのにかかった時間と直結しています。 対策 # SameSite Cookies (Lax) COOP Framing Protections Isolation Policies ❌ ❌ ❌ ❌ info
partitioned cachesと同様に、リソースの"site/originごとの分割"の原理をソケットプールに拡張することを、いくつかのブラウザが検討しています。 参考文献 #