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.club.tw?a=b&c=d";
console.log(anchor.outerHTML); // output: "<a href='https://mdn.club.tw?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