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

标签 html metrics depth

我想允许嵌入 HTML 但要避免 DoS,因为深度嵌套的 HTML 文档会使某些浏览器崩溃。我希望能够容纳 99.9% 的文档,但拒绝嵌套太深的文档。

两个密切相关的问题:

  1. 浏览器内置了哪些文档深度限制?例如。浏览器 X 无法解析或无法构建深度大于某个限制的文档。
  2. 网络上是否提供文档的文档深度统计信息?是否有网站提供网络统计信息,解释网络上一定百分比的真实文档的文档深度小于某个值。

文档深度定义为 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 测试测试。

最佳答案

可能值得询问 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 仍然崩溃。

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

  • Firefox 在 99 之后停止缩进列表项,这可能是编程限制。
  • Opera 一直在 250、376、502、628、754、880 处出现缩进问题...

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

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

看来,如果您打算允许用户发布在您的某个页面上呈现的 HTML,那么如果有足够的大小限制,则值得考虑对嵌套元素进行限制。

关于html - 实际中 HTML 文档的最大深度是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7770573/

相关文章:

javascript - 如何使 if 语句中的 "document.write"在同一 html 页面而不是新的空白页面上工作?

java - 如何在我正在编写的 Android 应用程序中从网站下载 HTML 代码?

spring-boot - 如何解决 "java.lang.illegalargumentexception collector already registered that provides name"?

Kinect 原始深度到距离(以米为单位)

algorithm - 那是一棵 n! 的二叉树吗?叶子的高度为 omega (n log n)

javascript - 在悬停时显示图像并将背景变灰

javascript - Div 标签不重新加载

amazon-web-services - AWS CloudWatch 指标数学与 30 分钟前的累积指标值以显示变化率

database - 指标与事件

xml - Dataweave - 循环深度映射 XML