实际中HTML文档的最大深度是多少?

时间:2011-10-14 16:21:12

标签: html metrics depth

我想允许嵌入HTML,但由于深度嵌套的HTML文档会导致某些浏览器崩溃,因此请避免使用DoS。我希望能够容纳99.9%的文件,但拒绝那些嵌套太深的文件。

两个密切相关的问题:

  1. 浏览器内置了哪些文档深度限制?例如。浏览器X无法解析或无法构建深度为>的文档。一些限制。
  2. 网络上是否有文档的文档深度统计信息?是否有一个网站统计数据可以解释网络上某些百分比的真实文档的文档深度低于某个值。
  3. 文档深度定义为1 +从文档中的任何节点到达文档根目录所需的最大父遍历数。例如,在

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

    最大深度为8,因为文本节点“Foo”有8个祖先。这里的祖先是非严格的解释,即节点是它自己的祖先和它自己的后代。

    Opera有一些表格嵌套统计信息,这表明99.99%的文档的表格嵌套深度小于22,但该数据不包含整个文档深度。

    编辑:

    如果有人想批评HTML清理库而不是回答这个问题,请这样做。 http://code.google.com/p/owasp-java-html-sanitizer/wiki/AttackReviewGroundRules解释了如何查找代码,在哪里找到可以尝试攻击的测试平台,以及如何报告问题。

    编辑:

    我问Adam Barth,他非常友好地指出了处理这个问题的webkit代码。

    至少Webkit强制执行此限制。当treebuildercreated时,它会收到可配置的树限制:

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

    并通过block-nesting-cap测试进行测试。

2 个答案:

答案 0 :(得分:19)

可能值得询问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中那样的性能下降。 / LI>
  • 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仍然会崩溃。

你可以在崩溃之前嵌套1409个列表项(<ul><li>),这是有趣的,因为:

  • Firefox会在99之后停止缩进列表项,这可能是编程约束。
  • 歌剧院继续缩进250,376,502,628,754,880 ......

设置DOCTYPE在IE8中有效(将其置于标准模式,即var outboundHtml = '<!DOCTYPE html>';):它不会嵌套792个列表项(选项卡崩溃/关闭)或1593个DIV。无论测试是从脚本生成还是从文件加载,IE8都没有区别。

因此浏览器的嵌套限制显然取决于攻击者注入的HTML元素的类型以及布局引擎。可能有一些HTML比这小得多。我们为IE8,Chrome和Safari用户提供了一个简单的HTML DoS,其负载相当小。

看起来如果您要允许用户发布在您的某个页面上呈现的HTML,如果存在大小限制,则值得考虑嵌套元素的限制。

答案 1 :(得分:4)

对于webkit,最大文档深度是可配置的,但默认情况下为512

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

static const unsigned defaultMaximumHTMLParserDOMTreeDepth = 512;