HTMLIFrameElement: srcdoc 属性
警告:此属性会将其输入解析为 HTML,并将结果写入 iframe 的 DOM。像这样的 API 被称为注入点,并且可能是跨站脚本 (XSS) 攻击的载体,如果输入最初来自攻击者。
您可以通过始终分配 TrustedHTML 对象而不是字符串并强制执行可信类型来减轻这种风险。有关更多信息,请参阅安全注意事项。
HTMLIFrameElement 接口的 srcdoc 属性用于获取或设置 iframe 文档的内联 HTML 标记。
值
获取此属性会返回一个包含 iframe 文档 HTML 序列化的字符串。如果未设置该值,则返回 undefined。
设置此属性可以接受 TrustedHTML 对象或字符串。它会将此输入解析为 HTML 文档,并用结果替换 iframe 的内容。
异常
描述
srcdoc 属性反映了 <iframe> 元素 srcdoc 属性的内容,并且可以用于设置或获取属于 <iframe> 的 HTML 文档。
设置此属性时,输入应定义一个有效的 HTML 文档,包括 文档类型声明、<html>、<body> 以及其他标签。但请注意,浏览器通常能容忍无效的标记,并且大多数浏览器应该会尝试渲染仅包含 body 内容的输入。
浏览器支持的任何标记都将被解析/序列化,包括Shadow 根。
请注意,如果设置了此属性,它将覆盖在 src 属性中设置的任何值。
安全注意事项
srcdoc 属性默认允许任何 HTML 标记在 iframe 中运行。如果 iframe 未使用内容安全策略 (CSP) 的 sandbox 指令进行沙箱化(或已沙箱化但包含 allow-same-origin 值),则它将与父级同源。这意味着 iframe 将完全访问父级 DOM 和资源,反之亦然。
如果用户提供的潜在不安全字符串未经验证就注入到 iframe 中,这将是跨站脚本 (XSS) 攻击的重要载体。考虑以下代码,其中来自用户的 HTML 字符串可能被传递到一个 iframe 中,然后该 iframe 被添加到文档中。
const untrustedStringFromUser = `<!doctype html><script src="http://evil.com/naughty.js"></script>`;
const iframe = document.createElement("iframe");
iframe.srcdoc = untrustedStringFromUser;
document.body.appendChild(iframe);
如果 iframe 不需要访问您的父文档,您可以通过使用不包含 allow-same-origin 值的 CSP 沙箱来降低风险。然后,iframe 将被视为跨域资源,攻击将受到显著限制。您也可以使用更通用的 CSP 来限制允许从何处获取脚本和其他资源。
您可以始终将 TrustedHTML 对象而不是字符串赋给 srcdoc,并使用 require-trusted-types-for CSP 指令强制执行可信类型,以进一步降低风险。这可确保输入通过转换函数,该函数有机会清理输入,在注入之前删除潜在的危险标记。
示例
从 iframe 读取 HTML
读取 srcdoc 会导致用户代理序列化 iframe 的文档。
给定以下 HTML
<frame
id="example"
srcdoc="<!doctype html><body><p>Hello World!</p></body>"></frame>
您可以按如下所示获取并记录标记
const frame = document.querySelector("#frame");
const frameDoc = frame.srcdoc;
console.log(frameDoc); // "<!doctype html><body><p>Hello World!</p></body>"
替换 iframe 的内联源
在此示例中,我们将通过将 HTML 分配给 iframe 的 srcdoc 属性来替换其文档。为降低 XSS 风险,我们将首先从包含 HTML 的字符串创建 TrustedHTML 对象,然后将该对象分配给 srcdoc。
Trusted Types 尚未在所有浏览器中得到支持,因此我们首先定义可信类型 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 =
"<!doctype html><body><p>I might be XSS</p><img src='x' onerror='alert(1)'></body>";
// Create a TrustedHTML instance using the policy
const trustedHTML = policy.createHTML(untrustedString);
// Inject the TrustedHTML (which contains a trusted string)
const frame = document.querySelector("#frame");
const frameDoc = frame.srcdoc;
规范
| 规范 |
|---|
| HTML # dom-iframe-srcdoc |
浏览器兼容性
加载中…