ShadowRoot: innerHTML 属性
警告:此属性将输入解析为 HTML,并将结果写入 DOM。像这样的 API 被称为注入槽,如果输入最初来自攻击者,它们可能是跨站脚本(XSS)攻击的潜在途径。
您可以通过始终分配 TrustedHTML 对象而不是字符串并强制执行可信类型来减轻这种风险。有关更多信息,请参阅安全注意事项。
ShadowRoot 接口的 innerHTML 属性用于获取或设置 ShadowRoot 内部 DOM 树的 HTML 标记。
值
获取该属性会返回一个字符串,其中包含阴影根(shadow root)的后代节点的 HTML 序列化表示。
设置该属性接受一个 TrustedHTML 对象或一个字符串。它会将此值解析为 HTML,并用解析结果替换元素的所有后代节点。当设置为 null 值时,该 null 值会被转换为空字符串(""),因此 shadowRoot.innerHTML = null 等同于 shadowRoot.innerHTML = ""。
异常
SyntaxErrorDOMException-
如果尝试使用格式不正确的 HTML 字符串来设置
innerHTML的值,将抛出此异常。 TypeError
描述
innerHTML 获取阴影根内嵌套的子 DOM 元素的序列化表示,或者设置应该被解析以替换阴影根内 DOM 树的 HTML 或 XML。
请注意,当 < 和 > 字符出现在属性值中时,某些浏览器会将其序列化为 < 和 >(请参阅浏览器兼容性)。这是为了防止潜在的安全漏洞(变异 XSS),其中攻击者可以精心构造绕过净化函数的输入,从而实现跨站脚本(XSS)攻击。
安全注意事项
innerHTML 属性是 跨站脚本(XSS)攻击的潜在攻击向量,在这种攻击中,用户提供的潜在不安全字符串会在未经验证的情况下注入 DOM。虽然该属性可以阻止注入的 <script> 元素执行,但它仍然容易受到攻击者精心构造的、用于运行恶意 JavaScript 的其他 HTML 方法的攻击。例如,下面的示例将在 error 事件处理程序中执行代码,因为 <img> 的 src 值不是有效的图像 URL。
const name = "<img src='x' onerror='alert(1)'>";
shadowRoot.innerHTML = name; // shows the alert
您可以通过始终分配 TrustedHTML 对象而不是字符串来缓解这些问题,并通过使用 require-trusted-types-for CSP 指令 强制执行受信任类型。这确保输入会通过一个转换函数,该函数有机会在注入之前 清理输入以移除潜在危险的标记。
示例
读取元素的 HTML 内容
读取 innerHTML 会导致用户代理序列化阴影根的后代节点。
给定以下 HTML
<div class="host">
<template shadowrootmode="open">
<p>My name is Joe</p>
</template>
</div>
您可以按照如下所示获取并记录阴影根的标记。
const shadowHost = document.querySelector("#host");
const shadowRoot = shadowHost.shadowRoot;
const contents = shadowRoot.innerHTML;
console.log(contents); // "\n <p>My name is Joe</p>\n"
设置 ShadowRoot 的 innerHTML
在此示例中,我们将通过将 HTML 分配给元素的 innerHTML 属性来替换元素的 DOM。为了降低 XSS 风险,我们将首先从包含 HTML 的字符串创建 TrustedHTML 对象,然后将该对象分配给 innerHTML。
受信任的类型尚未在所有浏览器中得到支持,因此我们首先定义 受信任类型 tinyfill。它充当受信任类型 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);
// Get the shadow root
const shadowHost = document.querySelector("#host");
const shadowRoot = shadowHost.shadowRoot;
// Inject the TrustedHTML (which contains a trusted string)
shadowRoot.innerHTML = trustedHTML;
警告:虽然您可以直接将字符串分配给 innerHTML,但这是一种 安全风险,如果待插入的字符串可能包含潜在的恶意内容。
规范
| 规范 |
|---|
| HTML # dom-shadowroot-innerhtml |
浏览器兼容性
加载中…