Trusted Types API

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

注意:此功能在 Web Workers 中可用。

Trusted Types API 為 Web 開發者提供了一種方法,可以確保在將輸入傳遞給可能執行該輸入的 API 之前,該輸入已透過使用者指定的轉換函式。這有助於防止客戶端 跨站指令碼 (XSS) 攻擊。最常見的轉換函式是 淨化輸入。

概念與用法

客戶端或基於 DOM 的 XSS 攻擊發生在攻擊者構造的資料被傳遞給將該資料作為程式碼執行的瀏覽器 API 時。這些 API 被稱為注入接收器

Trusted Types API 區分三種類型的注入接收器

防止基於 DOM 的 XSS 攻擊的主要方法之一是確保在將輸入傳遞給注入接收器之前將其進行安全處理。

在 Trusted Types API 中,開發者定義一個策略物件,其中包含轉換將要進入注入接收器的輸入以使其安全的方法。策略可以為不同型別的接收器定義不同的方法。

  • 對於 HTML 接收器,轉換函式通常會對輸入進行淨化,例如使用像 DOMPurify 這樣的庫。
  • 對於 JavaScript 和 JavaScript URL 接收器,策略可以完全停用這些接收器,或者允許某些預定義輸入(例如,特定的 URL)。

Trusted Types API 將確保在將輸入傳遞到接收器之前,會透過相應的轉換函式進行處理。

也就是說,該 API 使您能夠在一個地方定義策略,然後確信任何傳遞到注入接收器的資料都已透過該策略進行處理。

備註

Trusted Types API 本身提供策略或任何轉換函式:開發者定義自己的策略,其中包含他們希望應用的轉換。

該 API 有兩個主要部分

  • 一個 JavaScript API 使開發者能夠在將資料傳遞給注入接收器之前對其進行淨化。
  • 兩個 CSP 指令用於強制執行和控制 JavaScript API 的使用。

Trusted Types JavaScript API

在 Trusted Types API 中

  • 全域性屬性 trustedTypes,在 WindowWorker 上下文中都可用,用於建立 TrustedTypePolicy 物件。
  • 一個 TrustedTypePolicy 物件用於建立受信任的型別物件:它將透過轉換函式來處理資料。
  • 受信任的型別物件表示已透過策略處理的資料,因此可以安全地傳遞給注入接收器。有三種受信任的型別,對應於不同型別的注入接收器:
    • TrustedHTML 用於傳遞給將資料渲染為 HTML 的接收器。
    • TrustedScript 用於傳遞給將資料作為 JavaScript 執行的接收器。
    • TrustedScriptURL 用於傳遞給將資料解析為指令碼 URL 的接收器。

使用此 API,而不是將字串傳遞給 innerHTML 這樣的注入接收器,您可以使用 TrustedTypePolicy 從字串建立 TrustedHTML 物件,然後將其傳遞到接收器,這樣就可以確保字串已透過轉換函式。

例如,此程式碼建立了一個 TrustedTypePolicy,該策略可以透過 DOMPurify 庫淨化輸入字串來建立 TrustedHTML 物件。

js
const policy = trustedTypes.createPolicy("my-policy", {
  createHTML: (input) => DOMPurify.sanitize(input),
});

接下來,您可以使用此 policy 物件建立一個 TrustedHTML 物件,並將該物件傳遞到注入接收器。

js
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");

const trustedHTML = policy.createHTML(userInput);
element.innerHTML = trustedHTML;

使用 CSP 強制執行受信任型別

上面描述的 API 使您能夠淨化資料,但它不能確保您的程式碼永遠不會將輸入直接傳遞給注入接收器:也就是說,它不會阻止您將字串傳遞到 innerHTML

為了強制始終傳遞受信任的型別,您需要在您的 CSP 中包含 require-trusted-types-for 指令。設定此指令後,將字串傳遞到注入接收器將導致 TypeError 異常。

js
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");

element.innerHTML = userInput; // Throws a TypeError

此外,trusted-types CSP 指令可用於控制您的程式碼可以建立哪些策略。當您使用 trustedTypes.createPolicy() 建立策略時,會傳遞策略的名稱。trusted-types CSP 指令列出了可接受的策略名稱,因此如果 createPolicy() 傳遞了未在 trusted-types 中列出的名稱,它將丟擲異常。這可以防止您的 Web 應用程式中的某些程式碼建立您未預期的策略。

預設策略

在 Trusted Types API 中,您可以定義一個預設策略。這有助於您查詢程式碼中仍然將字串傳遞到注入接收器的位置,以便您可以重寫程式碼以建立並傳遞受信任的型別。

如果您建立一個名為 "default" 的策略,並且您的 CSP 強制使用受信任的型別,那麼傳遞到注入接收器的任何字串引數都將自動傳遞給此策略。例如,假設我們建立了一個如下策略:

js
trustedTypes.createPolicy("default", {
  createHTML(value) {
    console.log("Please refactor this code");
    return sanitize(value);
  },
});

使用此策略,如果您的程式碼將字串分配給 innerHTML,瀏覽器將呼叫策略的 createHTML() 方法並將其結果分配給接收器。

js
const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");

element.innerHTML = userInput;
// Logs "Please refactor this code"
// Assigns the result of sanitize(userInput)

如果預設策略返回 nullundefined,那麼當瀏覽器將結果分配給接收器時會丟擲 TypeError

js
trustedTypes.createPolicy("default", {
  createHTML(value) {
    console.log("Please refactor this code");
    return null;
  },
});

const userInput = "<p>I might be XSS</p>";
const element = document.querySelector("#container");

element.innerHTML = userInput;
// Logs "Please refactor this code"
// Throws a TypeError

注意: 建議僅在您從傳遞輸入到注入接收器的舊程式碼遷移到顯式使用受信任型別的程式碼時使用預設策略。

跨瀏覽器對受信任型別的支援

Trusted Types API 尚未在所有現代瀏覽器中可用,但由於 W3C 建立的相容性輔助工具,今天在任何地方都可以使用。

  • 完整 polyfill 定義了 JavaScript API,嘗試從當前文件推斷 CSP,並基於推斷的 CSP 強制使用受信任的型別。
  • 僅 API polyfill 僅定義了 JavaScript API,並且不包含使用 CSP 強制使用受信任型別的能力。

除了這兩個 polyfill 之外,W3C 還提供了所謂的迷你 polyfill,我們將在下面更詳細地解釋。

請注意,只要您在支援 CSP 強制執行的瀏覽器上測試過您的程式碼,那麼您就不需要在其他瀏覽器上使用上面的完整 polyfill —您可以使用僅 API polyfill迷你 polyfill 來獲得相同的優勢。

這是因為強制執行會迫使您重構程式碼,以確保所有資料在傳遞給注入接收器之前都已透過 Trusted Types API(因此已透過淨化函式)。如果您隨後在沒有強制執行的另一瀏覽器中執行重構後的程式碼,它仍然會經過相同的程式碼路徑,併為您提供相同的保護。

Trusted Types 迷你 polyfill

在本節中,我們將探討 trusted types 迷你 polyfill 如何保護網站,即使它根本不支援 trusted types。

trusted types 迷你 polyfill 就是這個:

js
if (typeof trustedTypes === "undefined")
  trustedTypes = { createPolicy: (n, rules) => rules };

它提供了 trustedTypes.createPolicy() 的實現,該實現僅返回它接收到的 policyOptions 物件。policyOptions 物件定義了資料的淨化函式,這些函式應返回字串。

在此迷你 polyfill 的基礎上,假設我們建立一個策略:

js
const policy = trustedTypes.createPolicy("my-policy", {
  createHTML: (input) => DOMPurify.sanitize(input),
});

在支援 trusted types 的瀏覽器中,這將返回一個 TrustedTypePolicy,當我們在呼叫 policy.createHTML() 時,它將建立一個 TrustedHTML 物件。然後可以將 TrustedHTML 物件傳遞給注入接收器,並且我們可以強制接收器接收的是一個受信任的型別,而不是一個字串。

在不支援 trusted types 的瀏覽器中,此程式碼將返回一個具有 createHTML() 函式的物件,該函式會淨化其輸入並將其作為字串返回。然後可以將淨化後的字串傳遞給注入接收器。

js
const userInput = "I might be XSS";
const element = document.querySelector("#container");

const trustedHTML = policy.createHTML(userInput);
// In supporting browsers, trustedHTML is a TrustedHTML object.
// In non-supporting browsers, trustedHTML is a string.

element.innerHTML = trustedHTML;
// In supporting browsers, this will throw if trustedHTML
// is not a TrustedHTML object.

無論哪種方式,注入接收器都會收到淨化後的資料,並且由於我們在支援的瀏覽器中可以強制使用該策略,因此我們知道在不支援的瀏覽器中,此程式碼路徑也會經過淨化函式。

介面

TrustedHTML

表示要插入到注入接收器中的字串,該接收器將把它渲染為 HTML。

TrustedScript

表示要插入到注入接收器中的字串,該注入接收器可能導致指令碼被執行。

TrustedScriptURL

表示要插入到注入接收器中的字串,該注入接收器將將其解析為外部指令碼資源的 URL。

TrustedTypePolicy

定義用於建立上述受信任型別物件的函式。

TrustedTypePolicyFactory

建立策略並驗證受信任型別物件例項是否透過其中一個策略建立。

示例

在下面的示例中,我們使用 TrustedTypePolicyFactory.createPolicy() 建立了一個將用於建立 TrustedHTML 物件的策略。然後,我們可以使用 TrustedTypePolicy.createHTML() 建立一個要插入到文件中的淨化後的 HTML 字串。

淨化後的值然後可以與 Element.innerHTML 一起使用,以確保不會注入新的 HTML 元素。

html
<div id="myDiv"></div>
js
const escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
  createHTML: (string) =>
    string
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&apos;"),
});

let el = document.getElementById("myDiv");
const escaped = escapeHTMLPolicy.createHTML("<img src=x onerror=alert(1)>");
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped;

有關此示例的更多資訊,以及發現其他淨化輸入的方法,請參閱文章 使用 Trusted Types 防止基於 DOM 的跨站指令碼漏洞

規範

規範
Trusted Types

瀏覽器相容性

另見