23

HTML の埋め込みを許可したいが、一部のブラウザーをクラッシュさせる深くネストされた HTML ドキュメントによる DoS を回避したい。99.9% のドキュメントに対応できるようにしたいのですが、入れ子が深すぎるドキュメントは拒否します。

2 つの密接に関連する質問:

  1. ブラウザーに組み込まれているドキュメントの深さの制限は? たとえば、ブラウザ X は解析に失敗するか、深さ > 制限のあるドキュメントを構築しません。
  2. 文書の文書深度統計は Web 上で入手できますか? Web 上の実際のドキュメントの一部のドキュメントの深さがある値よりも小さいことを説明する Web 統計のサイトはありますか。

ドキュメントの深さは、1 + ドキュメント内の任意のノードからドキュメント ルートに到達するために必要な親トラバーサルの最大数として定義されます。たとえば、

<html>                   <!-- 1 -->
  <body>                 <!-- 2 -->
    <div>                <!-- 3 -->
      <table>            <!-- 4 -->
        <tbody>          <!-- 5 -->
          <tr>           <!-- 6 -->
            <td>         <!-- 7 -->
              Foo        <!-- 8 -->

テキスト ノード "Foo" には 8 つの祖先があるため、最大深度は 8 です。ここでの祖先は非厳密に解釈されます。つまり、すべてのノードはそれ自身の祖先であり、それ自身の子孫です。

Operaにはいくつかのテーブル ネスト統計があり、ドキュメントの 99.99% が 22 未満のテーブル ネスト深度を持つことを示唆していますが、そのデータにはドキュメントの深度全体が含まれていません。

編集:

この質問に答える代わりに、HTML サニタイズ ライブラリを批判したい人がいたら、そうしてください。 http://code.google.com/p/owasp-java-html-sanitizer/wiki/AttackReviewGroundRulesでは、コードの見つけ方、攻撃を試すことができるテストベッドの場所、問題の報告方法について説明しています。

編集:

Adam Barth に尋ねたところ、これを処理する Webkit コードをとても親切に教えてくれました。

少なくとも、Webkit はこの制限を適用します。ツリービルダー作成されると、構成可能なツリー制限を受け取ります。

m_treeBuilder(HTMLTreeBuilder::create(this, document, reportErrors, usePreHTML5ParserQuirks(document), maximumDOMTreeDepth**(document)))

また、 block-nesting-capテストによってテストされます。

4

2 に答える 2

20

coderesearch@google.com に問い合わせる価値があるかもしれません。2005 年からの彼らの調査 ( http://code.google.com/webstats/ ) は、特定の質問をカバーしていません。ただし、彼らは 10 億を超えるドキュメントをサンプリングしており、調査する価値があると思われるものは何でも聞きたいと思っています。

- [アップデート] -

これは、私が持っているブラウザをテストするために書いた大雑把なスクリプトです (ネストする要素の数をクエリ文字列に入れます):

var n = Number(window.location.search.substring(1));

var outboundHtml = '';
var inboundHtml = '';

for(var i = 0; i < n; i++)
{
    outboundHtml += '<div>' + (i + 1);
    inboundHtml += '</div>';
}

var testWindow = window.open();
testWindow.document.open();
testWindow.document.write(outboundHtml + inboundHtml);
testWindow.document.close();

そして、ここに私の発見があります(私のマシン、Win XP、3Gb RAMに固有の可能性があります):

  • Chrome 9: 3218 のネストされた要素がレンダリングされ、3129 がタブをクラッシュさせます。(Chrome 9 は古いので、会社の LAN でアップデーターが失敗します)
  • Safari 5: 3477 がレンダリングされ、3478 ブラウザーが完全に閉じます。
  • IE8: 1000000+ がレンダリングされます (メモリが許す限り)。 ただし、4 桁の数値になると、スクロール/マウスの移動などのイベント バブリングにより、パフォーマンスが大幅に低下します。10000 を超えるものはすべてロックされているように見えますが、非常に長い時間がかかっているだけなので、効果的な DoS です
  • Opera 11: 私が知る限り、メモリによって制限されているだけです。つまり、私のスクリプトは 10000000 分のメモリを使い果たします。ただし、レンダリングする大きなドキュメントの場合、IE のようなパフォーマンスの低下はないようです。
  • Firefox 3.6: ~1500000 はレンダリングされますが、この範囲を超えてテストすると、ブラウザが Mozilla Crash Reporter でクラッシュするか、単にハングする結果になりました。機能した数値がその後失敗する場合がありましたが、~1700000 より大きい数値は、Firefox を再起動から直接クラッシュさせました。

Chrome の詳細:

DIV を SPAN に変更すると、Chrome はクラッシュする前に 9202 個の要素をネストできるようになりました。したがって、理由は HTML のサイズではありません (ただし、SPAN 要素はより軽量かもしれません)。

2077 個のテーブル セル ( <table><tr><td>) をネストすると (6231 要素)、セル 445 までスクロールするとクラッシュしたため、445 個のテーブル セル (1335 要素) をネストすることはできません。

(新しいウィンドウに書き込むのではなく) スクリプトから生成されたファイルを使用してテストすると、許容範囲がわずかに高くなりますが、Chrome は依然としてクラッシュしました。

<ul><li>クラッシュする前に1409 個のリスト アイテム ( ) をネストできます。これは興味深い理由です。

  • Firefox は 99 以降のリスト アイテムのインデントを停止します。おそらくプログラム上の制約です。
  • Opera は 250、376、502、628、754、880... でグリッチでインデントし続けます...

DOCTYPE の設定は IE8 で有効です (つまり、標準モードにしますvar outboundHtml = '<!DOCTYPE html>';): 792 個のリスト項目 (タブがクラッシュ/閉じる) または 1593 個の DIV をネストしません。IE8 では、テストがスクリプトから生成されたか、ファイルからロードされたかに違いはありませんでした。

したがって、ブラウザのネスト制限は、攻撃者が注入する HTML 要素のタイプとレイアウト エンジンに依存しているようです。これよりかなり小さい HTML がいくつかある可能性があります。また、IE8、Chrome、および Safari ユーザー向けのプレーン HTML DoS もあり、ペイロードはかなり小さいものです。

ユーザーがページの 1 つにレンダリングされる HTML を投稿できるようにする場合、サイズ制限が十分にある場合は、ネストされた要素の制限を検討する価値があるようです。

于 2011-10-14T20:34:04.793 に答える
4

Webkit の場合、ドキュメントの最大深度は構成可能ですが、デフォルトでは 512 です

http://trac.webkit.org/browser/trunk/Source/WebCore/page/Settings.h#L408

static const unsigned defaultMaximumHTMLParserDOMTreeDepth = 512;
于 2011-10-18T22:30:21.510 に答える