當來自使用者控制的來源 (例如使用者名稱,或從網址片段取得的重新導向網址) 的資料到達接收器時,就會發生 DOM 型跨網站指令碼 (DOM XSS)。接收器是可執行任意 JavaScript 程式碼的函式 (例如 eval()
) 或屬性設定器 (例如 .innerHTML
)。
DOM XSS 是最常見的網路安全漏洞之一,開發團隊經常會在應用程式中不慎導入這類漏洞。信任類型提供相關工具,可讓您編寫及安全審查應用程式,並預設確保危險的網頁 API 函式安全無虞,避免應用程式出現 DOM XSS 安全漏洞。對於尚未支援 Trusted Types 的瀏覽器,您可以透過 polyfill 使用這項功能。
背景
多年來,DOM XSS 一直是最常見且危險的網路安全漏洞之一。
跨網站指令碼攻擊分為兩種。部分 XSS 漏洞是由伺服器端程式碼所造成,這些程式碼會以不安全的方式建立構成網站的 HTML 程式碼。其他問題的根本原因在於用戶端,也就是 JavaScript 程式碼使用使用者控制的內容呼叫危險函式。
如要防止伺服器端 XSS,請勿透過串連字串產生 HTML。請改用安全的脈絡自動逸出範本程式庫,並搭配以隨機數值為基礎的內容安全政策,進一步減少錯誤。
現在瀏覽器也能使用 Trusted Types,協助防範用戶端 DOM 型 XSS 攻擊。
API 簡介
信任類型會鎖定下列有風險的接收器函式,您可能已經認識其中一些功能,因為瀏覽器供應商和網頁架構基於安全考量,已引導您避免使用這些功能。
- 指令碼操控:
<script src>
並設定<script>
元素的文字內容。 - 從字串產生 HTML:
- 執行外掛程式內容:
- 執行階段 JavaScript 程式碼編譯:
eval
setTimeout
setInterval
new Function()
您必須先處理資料,再將資料傳遞至這些接收器函式。如果只使用字串,系統會失敗,因為瀏覽器不知道資料是否值得信任:
anElement.innerHTML = location.href;
如要表示資料已安全處理,請建立特殊物件 (即「信任型別」)。
anElement.innerHTML = aTrustedHTML;
TrustedHTML
物件,用於需要 HTML 程式碼片段的接收器。此外,還有其他敏感接收器的 TrustedScript
和 TrustedScriptURL
物件。
Trusted Types 可大幅縮減應用程式的 DOM XSS 攻擊面。這項功能可簡化安全性審查,並在瀏覽器中編譯、Lint 或組合程式碼時,強制執行以型別為基礎的安全性檢查。
如何使用信任的型別
準備接收內容安全政策違規報告
您可以部署報表收集器,例如開放原始碼的 reporting-api-processor 或 go-csp-collector,也可以使用其中一個商業對等項目。您也可以使用 ReportingObserver 在瀏覽器中新增自訂記錄,並偵錯違規事項:
const observer = new ReportingObserver((reports, observer) => {
for (const report of reports) {
if (report.type !== 'csp-violation' ||
report.body.effectiveDirective !== 'require-trusted-types-for') {
continue;
}
const violation = report.body;
console.log('Trusted Types Violation:', violation);
// ... (rest of your logging and reporting logic)
}
}, { buffered: true });
observer.observe();
或新增事件監聽器:
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
新增僅供回報的 CSP 標頭
在要遷移至安全類型的文件中,加入下列 HTTP 回應標頭:
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
現在所有違規事項都會回報給 //my-csp-endpoint.example
,但網站仍可正常運作。下一節將說明 //my-csp-endpoint.example
的運作方式。
找出 Trusted Types 違規問題
從現在起,每當「信任類型」偵測到違規行為,瀏覽器就會將報告傳送至已設定的 report-uri
。舉例來說,當應用程式將字串傳遞至 innerHTML
時,瀏覽器會傳送下列報表:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
這表示第 39 行的 https://my.url.example/script.js
中,innerHTML
是以開頭為 <img src=x
的字串呼叫。這項資訊有助於縮小範圍,找出可能導致 DOM XSS 的程式碼部分,並進行變更。
修正違規事項
修正 Trusted Types 違規問題的方法有幾種。您可以移除違規程式碼、使用程式庫、建立 Trusted Type 政策,或最後建立預設政策。
重寫違規程式碼
不符規定的程式碼可能已不需要,或可重新編寫,且不含導致違規的函式:
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
el.innerHTML = '<img src=xyz.jpg>';
使用程式庫
部分程式庫已產生可傳遞至接收器函式的 Trusted Types。舉例來說,您可以使用 DOMPurify 清理 HTML 程式碼片段,移除 XSS 酬載。
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify 支援 Trusted Types,並傳回包裝在 TrustedHTML
物件中的經過清理的 HTML,因此瀏覽器不會產生違規情形。
建立 Trusted Types 政策
有時您無法移除導致違規的程式碼,也沒有可清除值並為您建立 Trusted Type 的程式庫。在這種情況下,您可以自行建立 Trusted Type 物件。
首先,請建立政策。 政策是 Trusted Types 的工廠,可對輸入內容強制執行特定安全性規則:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
這段程式碼會建立名為 myEscapePolicy
的政策,可使用 createHTML()
函式產生 TrustedHTML
物件。定義的規則會逸出 <
字元,避免建立新的 HTML 元素。
請按照下列方式使用政策:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
使用預設政策
有時您無法變更違規程式碼,例如從 CDN 載入第三方程式庫時。在這種情況下,請使用預設政策:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
凡是在只接受 Trusted Type 的接收器中使用字串,都會用到名為 default
的政策。
切換為強制執行內容安全政策
應用程式不再產生違規行為後,即可開始強制執行 Trusted Types:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
現在,無論網頁應用程式有多複雜,唯一可能導致 DOM XSS 漏洞的,就是其中一項政策中的程式碼,而且您還可以限制政策建立作業,進一步防範這類漏洞。