Element:innerHTML 属性

Baseline 广泛可用 *

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

* 此特性的某些部分可能存在不同级别的支持。

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

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

Element 接口的 innerHTML 属性用于获取或设置元素中包含的 HTML 或 XML 标记,这两种情况下都省略任何影子根

要将 HTML 插入到文档中,而不是替换元素的内容,请使用方法insertAdjacentHTML()

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

设置该属性接受TrustedHTML 对象或字符串。它会将此值解析为 HTML,并用结果替换所有元素的后代。当设置为 null 值时,该 null 值将转换为空字符串(""),因此 elt.innerHTML = null 等同于 elt.innerHTML = ""

异常

SyntaxError DOMException

如果尝试使用格式不正确的 HTML 字符串设置 innerHTML 的值,则抛出此错误。

TypeError

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

NoModificationAllowedError DOMException

如果尝试将 HTML 插入到其父级为Document的节点中,则抛出此错误。

描述

innerHTML 获取元素内嵌套子 DOM 元素的序列化,或设置应解析为替换元素内 DOM 树的 HTML 或 XML。

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

影子 DOM 考虑

从属性读取的 DOM 树的序列化不包括影子根——如果您想获取包含影子根的 HTML 字符串,则必须改用Element.getHTML()ShadowRoot.getHTML() 方法。

同样,当使用 innerHTML 设置元素内容时,HTML 字符串会被解析为不包含影子根的 DOM 元素。因此,例如,<template> 会被解析为 HTMLTemplateElement,无论是否指定了shadowrootmode 属性。为了从包含声明性影子根的 HTML 字符串设置元素内容,您必须改用 Element.setHTMLUnsafe()ShadowRoot.setHTMLUnsafe()

安全注意事项

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

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

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

注意:当您知道用户提供的内容应该是纯文本时,应使用Node.textContent。这可以防止它被解析为 HTML。

示例

读取元素的 HTML 内容

读取 innerHTML 会导致用户代理序列化元素的后代。

给定以下 HTML

html
<div id="example">
  <p>My name is Joe</p>
</div>

您可以获取并记录外部<div>内容标记,如下所示:

js
const myElement = document.querySelector("#example");
const contents = myElement.innerHTML;
console.log(contents); // "\n  <p>My name is Joe</p>\n"

替换元素的内容

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

可信类型尚未在所有浏览器中受支持,因此我们首先定义可信类型小型填充。这可以作为可信类型 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.innerHTML = trustedHTML;

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

规范

规范
HTML
# dom-element-innerhtml

浏览器兼容性

另见