Document: write() 方法

已棄用:此特性不再推薦。雖然某些瀏覽器可能仍然支援它,但它可能已經從相關的網路標準中刪除,可能正在刪除過程中,或者可能僅為相容性目的而保留。請避免使用它,如果可能,請更新現有程式碼;請參閱本頁底部的相容性表格以指導您的決策。請注意,此特性可能隨時停止工作。

警告:強烈不建議使用 document.write() 方法。請避免使用它,並儘可能在現有程式碼中替換它。

正如 HTML 規範本身所警告的

此方法具有非常特殊的行為。在某些情況下,此方法可以在解析器執行時影響 HTML 解析器 的狀態,從而導致 DOM 不對應於文件的原始碼(例如,如果寫入的字串是字串 "<plaintext>" 或 "<!--")。在其他情況下,此呼叫可能會首先清除當前頁面,就像呼叫了 document.open() 一樣。在更多情況下,此方法被簡單地忽略,或丟擲異常。使用者代理 明確允許避免執行透過此方法插入的 script 元素。更糟糕的是,此方法的精確行為在某些情況下可能取決於網路延遲,這可能導致非常難以除錯的故障。出於所有這些原因,強烈不建議使用此方法。

警告:此方法將其輸入解析為 HTML,並將結果寫入 DOM。此類 API 被稱為 注入槽,如果輸入最初來自攻擊者,則可能成為 跨站點指令碼 (XSS) 攻擊的載體。

您可以透過始終傳遞 TrustedHTML 物件而不是字串並 強制執行可信型別 來緩解此風險。有關更多資訊,請參閱 安全注意事項

Document 介面的 write() 方法將一個或多個 TrustedHTML 或字串引數中的文字寫入透過 document.open() 開啟的文件流。

語法

js
write(markup)
write(markup, markup2)
write(markup, markup2, /* …, */ markupN)

引數

markup, …, markupN

TrustedHTML 物件或包含要寫入文件的標記的字串。

返回值

無(undefined)。

異常

InvalidStateError DOMException

在 XML 文件上呼叫了該方法,或者在解析器當前正在執行自定義元素建構函式時呼叫了該方法。

TypeError

強制執行可信型別 並且 沒有定義預設策略 來建立 TrustedHTML 物件時,字串作為其中一個引數傳遞。

描述

document.write() 將作為引數傳遞的物件的標記文字按照引數指定的順序解析到開啟文件的物件模型 (DOM) 中。

由於 document.write() 寫入到文件,因此在關閉(已載入)文件上呼叫 document.write()(而未首先呼叫 document.open())會自動呼叫 document.open(),這將清除文件。

例外情況是,如果 document.write() 呼叫嵌入在內聯 HTML <script> 標籤中,則它不會自動呼叫 document.open()

html
<script>
  document.write("<h1>Main title</h1>");
</script>

document.write() (和 document.writeln) 不能與 XML 或 XHTML 一起使用,嘗試這樣做將丟擲 InvalidStateError 異常。如果開啟帶有 .xhtml 副檔名的本地檔案,或對於任何帶有 application/xhtml+xml MIME 型別服務的文件,情況都是如此。更多資訊可在 W3C XHTML FAQ 中找到。

延遲非同步 指令碼中使用 document.write() 將被忽略,並且您將在錯誤控制檯中收到類似“來自非同步載入的外部指令碼的 document.write() 呼叫被忽略”的訊息。

僅在 Edge 中,在 <iframe> 中多次呼叫 document.write() 會導致錯誤“SCRIPT70: 許可權被拒絕”。

安全注意事項

該方法是 跨站指令碼 (XSS) 攻擊的潛在途徑,其中使用者提供的潛在不安全字串在未首先進行清理的情況下被注入到 DOM 中。雖然該方法可能會阻止 <script> 元素在某些瀏覽器中被注入時執行(有關 Chrome 的資訊,請參閱 Intervening against document.write()),但它容易受到攻擊者精心構造 HTML 以執行惡意 JavaScript 的許多其他方式的影響。

您可以透過始終傳遞 TrustedHTML 物件而不是字串,並使用 require-trusted-types-for CSP 指令強制執行可信型別 來緩解這些問題。這確保了輸入透過轉換函式,該函式有機會清理輸入以刪除潛在危險的標記(例如 <script> 元素和事件處理程式屬性),然後再注入。

示例

寫入 TrustedHTML

此示例使用 Trusted Types API 在將 HTML 字串寫入文件之前清理其中的 <script> 元素。

該示例最初顯示一些預設文字和一個按鈕。當點選按鈕時,當前文件將被開啟,三個 HTML 字串被轉換為 TrustedHTML 例項並寫入文件,然後文件被關閉。這替換了示例框架中的文件,包括按鈕的原始 HTML 和執行更新的 JavaScript!

HTML

html
<p>Some original document content.</p>
<button id="replace" type="button">Replace document content</button>

JavaScript

首先,我們使用 Window.trustedTypes 屬性訪問全域性 TrustedTypePolicyFactory,並使用其 createPolicy() 方法定義名為 "docPolicy" 的策略。

新策略定義了一個轉換函式 createHTML(),用於建立我們將傳遞給 write() 方法的 TrustedHTML 物件。此方法可以隨意處理輸入字串:可信型別 API 只要求您透過策略轉換函式傳遞輸入,而不是要求轉換函式執行任何特定操作。

您可以使用該方法透過刪除潛在不安全的功能(例如 <script> 標籤或事件處理程式屬性)來清理輸入。清理很難做好,因此此過程通常使用信譽良好的第三方庫,例如 DOMPurify

出於演示目的,我們在此實現一個簡陋的“清理器”,它將指令碼開始和結束標籤中的 < 符號替換為 &lt; 字元。

js
const policy = trustedTypes.createPolicy("docPolicy", {
  createHTML(string) {
    return string
      .replace("<script", "&lt;script")
      .replace("</script", "&lt;/script");
  },
});

然後,我們可以對返回的策略使用 TrustedTypePolicy.createHTML() 方法,從原始輸入字串建立 TrustedHTML 物件。當用戶點選按鈕時,這些物件會傳遞給 write() 函式。

js
const oneInput = "<h1>Out with the old</h1>";
const twoInput = "<p>in with the new!</p>";
const threeInput = "<script>alert('evil afoot')<" + "/script>";
const replace = document.querySelector("#replace");

replace.addEventListener("click", () => {
  document.open();
  document.write(
    policy.createHTML(oneInput),
    policy.createHTML(twoInput),
    policy.createHTML(threeInput),
  );
  document.close();
});

結果

按下按鈕並注意,我們信任(在此示例中)的 HTML 元素被注入,但不受信任的 <script> 元素現在以純文字形式呈現。

寫入字串

這與前面的示例相同,只是未使用或強制執行可信型別。我們正在寫入未清理的字串,這可能為 XSS 攻擊 提供途徑。

此示例最初顯示一些預設文字和一個按鈕。當點選按鈕時,當前文件將被開啟,三個 HTML 字串被寫入文件,然後文件被關閉。這替換了示例框架中的文件,包括按鈕的原始 HTML 和執行更新的 JavaScript。

HTML

html
<p>Some original document content.</p>
<button id="replace" type="button">Replace document content</button>

JavaScript

js
const replace = document.querySelector("#replace");

const oneInput = "<h1>Out with the old</h1>";
const twoInput = "<p>in with the new!</p>";
const threeInput = "<script>alert('evil afoot')<" + "/script>";

replace.addEventListener("click", () => {
  document.open();
  document.write(oneInput, twoInput, threeInput);
  document.close();
});

結果

按下按鈕,並注意所有 HTML 元素都被注入。這包括 <script> 元素,它在實際應用程式中可能會執行有害程式碼。

規範

規範
HTML
# dom-document-write-dev

瀏覽器相容性

另見