Element:outerHTML 属性
警告:此属性将输入解析为 HTML,并将结果写入 DOM。像这样的 API 被称为注入槽,如果输入最初来自攻击者,它们可能是跨站脚本(XSS)攻击的潜在途径。
您可以通过始终分配 TrustedHTML 对象而不是字符串并强制执行可信类型来减轻这种风险。有关更多信息,请参阅安全注意事项。
Element 接口的 outerHTML 属性获取或设置元素及其后代的 HTML 或 XML 标记,这两种情况下都会省略任何影子根。
要获取或设置元素的内容,请改用 innerHTML 属性。
值
获取此属性会返回一个字符串,其中包含 element 及其后代的 HTML 序列化。
设置此属性接受 TrustedHTML 对象或字符串。输入被解析为 HTML 并替换元素及其所有后代。当设置为 null 值时,该 null 值将转换为空字符串(""),因此 element.outerHTML = null 等同于 element.outerHTML = ""。
异常
NoModificationAllowedErrorDOMException-
如果尝试在作为
Document的直接子元素的元素(例如Document.documentElement)上设置outerHTML,则会抛出此错误。 SyntaxErrorDOMException-
如果尝试使用格式不正确的 XML 输入设置
outerHTML,则会抛出此错误。 TypeError
描述
outerHTML 获取元素的序列化,或者设置应解析的 HTML 或 XML,以替换元素父级中的元素。
如果元素没有父节点,设置其 outerHTML 属性将不会更改它或其后代。例如
const div = document.createElement("div");
div.outerHTML = '<div class="test">test</div>';
console.log(div.outerHTML); // output: "<div></div>"
此外,虽然元素将在文档中被替换,但其 outerHTML 属性被设置的变量仍将保留对原始元素的引用
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 属性中的某些值。此处我们看到 & 字符被转义
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&c=d'></a>"
一些浏览器还将属性值中出现的 < 和 > 字符序列化为 < 和 >(参见浏览器兼容性)。这是为了防止潜在的安全漏洞(变异 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
const name = "<img src='x' onerror='alert(1)'>";
element.outerHTML = name; // shows the alert
您可以通过始终分配 TrustedHTML 对象而不是字符串,并通过 require-trusted-types-for CSP 指令强制执行可信类型来缓解这些问题。这确保输入通过转换函数传递,该函数有机会在注入之前净化输入以删除潜在危险的标记。
示例
获取元素的序列化
读取 outerHTML 会导致用户代理序列化元素。
给定以下 HTML
<div id="example">
<p>Content</p>
<p>Further Elaborated</p>
</div>
您可以按所示获取并记录 <div> 的标记
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 的透明替代品。
if (typeof trustedTypes === "undefined")
trustedTypes = { createPolicy: (n, rules) => rules };
接下来,我们创建一个 TrustedTypePolicy,它定义了一个 createHTML(),用于将输入字符串转换为 TrustedHTML 实例。通常,createHTML() 的实现使用像 DOMPurify 这样的库来清理输入,如下所示
const policy = trustedTypes.createPolicy("my-policy", {
createHTML: (input) => DOMPurify.sanitize(input),
});
然后我们使用这个 policy 对象从潜在不安全的输入字符串创建 TrustedHTML 对象,并将结果分配给元素。
// 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,
规范
| 规范 |
|---|
| HTML # dom-element-outerhtml |
浏览器兼容性
加载中…
另见
- 将 DOM 树序列化为 XML 字符串:
XMLSerializer - 将 XML 或 HTML 解析为 DOM 树:
DOMParser HTMLElement.outerText