Element:outerHTML 属性

Baseline 已广泛支持

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

警告:此属性将输入解析为 HTML,并将结果写入 DOM。像这样的 API 被称为注入槽,如果输入最初来自攻击者,它们可能是跨站脚本(XSS)攻击的潜在途径。

您可以通过始终分配 TrustedHTML 对象而不是字符串并强制执行可信类型来减轻这种风险。有关更多信息,请参阅安全注意事项

Element 接口的 outerHTML 属性获取或设置元素及其后代的 HTML 或 XML 标记,这两种情况下都会省略任何影子根

要获取或设置元素的内容,请改用 innerHTML 属性。

获取此属性会返回一个字符串,其中包含 element 及其后代的 HTML 序列化。

设置此属性接受 TrustedHTML 对象或字符串。输入被解析为 HTML 并替换元素及其所有后代。当设置为 null 值时,该 null 值将转换为空字符串(""),因此 element.outerHTML = null 等同于 element.outerHTML = ""

异常

NoModificationAllowedError DOMException

如果尝试在作为 Document 的直接子元素的元素(例如 Document.documentElement)上设置 outerHTML,则会抛出此错误。

SyntaxError DOMException

如果尝试使用格式不正确的 XML 输入设置 outerHTML,则会抛出此错误。

TypeError

如果在可信类型CSP 强制执行且未定义默认策略时将属性设置为字符串,则抛出此错误。

描述

outerHTML 获取元素的序列化,或者设置应解析的 HTML 或 XML,以替换元素父级中的元素。

如果元素没有父节点,设置其 outerHTML 属性将不会更改它或其后代。例如

js
const div = document.createElement("div");
div.outerHTML = '<div class="test">test</div>';
console.log(div.outerHTML); // output: "<div></div>"

此外,虽然元素将在文档中被替换,但其 outerHTML 属性被设置的变量仍将保留对原始元素的引用

js
const p = document.querySelector("p");
console.log(p.nodeName); // shows: "P"
p.outerHTML = "<div>This div replaced a paragraph.</div>";
console.log(p.nodeName); // still "P";

转义属性值

返回的值将转义 HTML 属性中的某些值。此处我们看到 & 字符被转义

js
const anchor = document.createElement("a");
anchor.href = "https://mdn.org.cn?a=b&c=d";
console.log(anchor.outerHTML); // output: "<a href='https://mdn.org.cn?a=b&amp;c=d'></a>"

一些浏览器还将属性值中出现的 <> 字符序列化为 &lt;&gt;(参见浏览器兼容性)。这是为了防止潜在的安全漏洞(变异 XSS),攻击者可以精心制作输入以绕过净化函数,从而实现跨站脚本 (XSS) 攻击。

Shadow DOM 考虑事项

从属性读取的 DOM 树的序列化不包括影子根。如果要获取包含影子根的元素的 HTML 序列化,则必须改用 Element.getHTML() 方法。请注意,这将获取元素的内容

类似地,当使用 outerHTML 设置元素内容时,HTML 输入会被解析为不包含影子根的 DOM 元素。例如,<template> 会被解析为 HTMLTemplateElement,无论是否指定了 shadowrootmode 属性。如果您想使用包含声明性影子根的 HTML 输入来设置元素的内容,则必须改用 Element.setHTMLUnsafe()ShadowRoot.setHTMLUnsafe()

安全注意事项

outerHTML 属性是跨站脚本 (XSS) 攻击的潜在载体,因为它可用于将用户提供的潜在不安全字符串注入 DOM。虽然该属性确实阻止了 <script> 元素在注入时执行,但它容易受到攻击者精心制作 HTML 以运行恶意 JavaScript 的许多其他方式的影响。例如,以下示例将执行 error 事件处理程序中的代码,因为 <img> src 值不是有效的图像 URL

js
const name = "<img src='x' onerror='alert(1)'>";
element.outerHTML = name; // shows the alert

您可以通过始终分配 TrustedHTML 对象而不是字符串,并通过 require-trusted-types-for CSP 指令强制执行可信类型来缓解这些问题。这确保输入通过转换函数传递,该函数有机会在注入之前净化输入以删除潜在危险的标记。

示例

获取元素的序列化

读取 outerHTML 会导致用户代理序列化元素。

给定以下 HTML

html
<div id="example">
  <p>Content</p>
  <p>Further Elaborated</p>
</div>

您可以按所示获取并记录 <div> 的标记

js
const myElement = document.querySelector("#example");
const contents = myElement.outerHTML;
console.log(contents);
// '<div id="example">\n  <p>Content</p>\n  <p>Further Elaborated</p>\n</div>'

替换元素

在此示例中,我们将通过将 HTML 分配给元素的 outerHTML 属性来替换 DOM 中的元素。为了减轻 XSS 的风险,我们将首先从包含 HTML 的字符串创建一个 TrustedHTML 对象,然后将该对象分配给 outerHTML

可信类型尚未在所有浏览器中受支持,因此我们首先定义可信类型小型填充。这可以作为可信类型 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 对象,并将结果分配给元素。

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);

// Inject the TrustedHTML (which contains a trusted string)
const element = document.querySelector("#container");
element.outerHTML = trustedHTML; // Replaces the element with id "container"

// Note that the  #container div is no longer part of the document tree,

警告:虽然您可以直接将字符串分配给 outerHTML,但如果要插入的字符串可能包含潜在恶意内容,这会带来安全风险。您应该使用 TrustedHTML 来确保内容在插入之前经过净化,并且应该设置 CSP 头部以强制执行可信类型

规范

规范
HTML
# dom-element-outerhtml

浏览器兼容性

另见