DOMParser: parseFromString() 方法

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

警告:此方法将其输入解析为 HTML,并将结果写入 DOM。此类 API 被称为 注入槽,如果输入最初来自攻击者,则可能成为 跨站点脚本 (XSS) 攻击的载体。

您可以通过始终传递 TrustedHTML 对象而不是字符串并 强制执行可信类型 来缓解此风险。有关更多信息,请参阅 安全注意事项

DOMParser 接口的 parseFromString() 方法会解析包含 HTML 或 XML 的输入,并返回一个 Document 对象,该对象的 contentType 属性与 contentType 参数匹配。

注意: Document.parseHTMLUnsafe() 静态方法提供了一种更简洁的方式来将 HTML 标记解析为 Document 对象。

语法

js
parseFromString(input, mimeType)

参数

input

一个 TrustedHTML 或字符串实例,用于定义要解析的 HTML。标记必须包含一个 HTMLXMLXHTMLSVG 文档。

mimeType

一个字符串,指定使用 XML 解析器还是 HTML 解析器来解析字符串。

允许的值为

  • text/html
  • text/xml
  • application/xml
  • application/xhtml+xml
  • image/svg+xml

返回值

一个 Document 对象,其 contentType 与给定的 mimeType 匹配。

注意: 浏览器可能实际上返回一个 HTMLDocumentXMLDocument 对象。它们都继承自 Document 且不添加任何属性:它们本质上是等价的。

异常

TypeError

当以下情况发生时会抛出此异常:

描述

parseFromString() 方法会解析包含 HTML 或 XML 的输入,并返回一个 Document 对象,其 contentTypemimeType 匹配。这个 Document 包含一个完整的内存 DOM,该 DOM 与关联页面中的主文档是分开的。

如果 mimeTypetext/html,则输入将作为 HTML 解析,并且 <script> 元素将被标记为非可执行状态,事件不会被触发,内联脚本的事件处理程序也不会被调用。虽然文档可以下载 <iframe><img> 元素中指定的资源,但它本质上是惰性的。这很有用,因为您可以解析包含 声明性 Shadow DOM 的 HTML 输入,并在不影响可见页面的情况下对文档执行操作。例如,您可以使用此方法清理输入树,并在需要时将输入的部分注入到可见 DOM 中。

对于其他允许的值(text/xmlapplication/xmlapplication/xhtml+xmlimage/svg+xml),输入将作为 XML 解析。如果您想导入 XML 文件、验证其结构并提取数据,这很有用。如果输入不代表格式良好的 XML,则返回的文档将包含一个 <parsererror> 节点,描述解析错误的性质。

不允许的 mimeType 值会导致 TypeError 被抛出。

安全注意事项

此方法将输入解析到单独的内存 DOM 中,禁用任何 <script> 元素,并阻止事件处理程序运行。虽然返回的文档实际上是惰性的,但如果 DOM 中的事件处理程序和脚本被插入到可见 DOM 中,它们将能够运行。因此,该方法可能成为 跨站脚本攻击 (XSS) 的一个向量,在这种攻击中,潜在不安全的输入会先被解析到 Document 而未经清理,然后被注入到可见/活动 DOM 中,从而使代码能够运行。

您应该通过始终传递 TrustedHTML 对象而不是字符串,并使用 require-trusted-types-for CSP 指令强制执行受信任类型来降低此风险。这确保了输入通过转换函数,该函数有机会清理输入以移除潜在危险的标记(例如 <script> 元素和事件处理程序属性),然后才注入。

使用 TrustedHTML 可以仅在少数几个地方审计和检查清理代码是否有效,而不是分散在所有注入点。在使用 TrustedHTML 时,您通常不需要将清理程序传递给该方法。

请注意,即使您对可以执行代码的元素和属性的输入进行了清理,您在处理任何用户输入时仍需谨慎。例如,您的页面可能会使用 XML 文档中的数据来获取它随后执行的文件。

示例

使用 Trusted Types 解析输入

在此示例中,我们将安全地解析潜在有害的 HTML 输入,然后将其注入到可见页面的 DOM 中。

为了减轻 XSS 风险,我们将从包含 HTML 的字符串创建一个 TrustedHTML 对象。Trusted Types 尚未在所有浏览器中得到支持,因此我们首先定义 trusted types tinyfill。它充当 Trusted Types JavaScript API 的透明替代品。

js
if (typeof trustedTypes === "undefined")
  trustedTypes = { createPolicy: (n, rules) => rules };

接下来,我们创建一个 TrustedTypePolicy,它定义了一个 createHTML() 方法,用于将输入字符串转换为 TrustedHTML 实例。通常,createHTML() 的实现会使用像 DOMPurify 这样的库来清理输入,如下所示。

js
const policy = trustedTypes.createPolicy("my-policy", {
  createHTML: (input) => DOMPurify.sanitize(input),
});

然后,我们使用此 policy 对象从潜在不安全的输入字符串创建 TrustedHTML 对象,并将其解析为 Document。请注意,即使输入不包含这些元素,生成的 Document 仍将表示一个包含根 <html><head><body> 的完整 HTML 文档。

js
// The potentially malicious string
const untrustedString = "<p>I might be XSS</p><img src='x' onerror='alert(1)'>";

// Create a TrustedHTML instance using the policy
const trustedHTML = policy.createHTML(untrustedString);

// Parse the TrustedHTML (which contains a trusted string)
const safeDocument = parser.parseFromString(trustedHTML, "text/html");

现在,safeDocument 包含一个根据我们的策略清理了有害元素的 DOM。下面,我们使用 Element.replaceWith() 将可见 DOM 的 body 替换为我们文档的 body:新 body 中的脚本将运行,事件处理程序触发时代码也将运行。

js
document.body.replaceWith(safeDocument.body);

解析 XML、SVG 和 HTML

下面的代码展示了如何使用该方法解析每种内容类型。虽然在实际代码中应使用 Trusted Types,但此处为简洁起见省略了它们。

js
const parser = new DOMParser();

const xmlString = "<warning>Beware of the tiger</warning>";
const doc1 = parser.parseFromString(xmlString, "application/xml");
console.log(doc1.contentType); // "application/xml"

const svgString = '<circle cx="50" cy="50" r="50"/>';
const doc2 = parser.parseFromString(svgString, "image/svg+xml");
console.log(doc2.contentType); // "image/svg+xml"

const htmlString = "<strong>Beware of the leopard</strong>";
const doc3 = parser.parseFromString(htmlString, "text/html");
console.log(doc3.contentType); // "text/html"

console.log(doc1.documentElement.textContent);
// "Beware of the tiger"

console.log(doc2.firstChild.tagName);
// "circle"

console.log(doc3.body.firstChild.textContent);
// "Beware of the leopard"

请注意,上面的 application/xmlimage/svg+xml MIME 类型在功能上是相同的——后者不包含任何 SVG 特定解析规则。

错误处理

当使用 XML 解析器处理不代表格式良好 XML 的字符串时,parseFromString 返回的 XMLDocument 将包含一个 <parsererror> 节点,描述解析错误的性质。

js
const parser = new DOMParser();

const xmlString = "<warning>Beware of the missing closing tag";
const doc = parser.parseFromString(xmlString, "application/xml");
const errorNode = doc.querySelector("parsererror");
if (errorNode) {
  // parsing failed
} else {
  // parsing succeeded
}

此外,解析错误可能会报告到浏览器的 JavaScript 控制台。

规范

规范
HTML
# dom-domparser-parsefromstring-dev

浏览器兼容性

另见