論壇、部落格、CMS 等系統常需允許使用者輸入 HTML 標籤(如 <b>、<img>)以豐富排版,但必須嚴防惡意腳本注入(XSS)。單純使用 HtmlEncode 會連合法 HTML 一起轉義,導致排版功能失效。本文提供基於正則表達式的過濾方案,保留安全 HTML 標籤,移除危險腳本向量。
onclick、onload、onmouseover 等 on* 屬性<a href="javascript:...">、<img src="javascript:...">public string WipeScript(string html)
{
if (string.IsNullOrEmpty(html)) return html;
// 1. 移除 區塊(含跨行)
var regexScript = new Regex(@"<script[\s\S]*?</script\s*>", RegexOptions.IgnoreCase);
html = regexScript.Replace(html, "");
// 2. 移除 href/src 等屬性中的 javascript: 偽協議
var regexJsProtocol = new Regex(@"\b(href|src|action)\s*=\s*[\s\S]*?\bjavascript\s*:", RegexOptions.IgnoreCase);
html = regexJsProtocol.Replace(html, "");
// 3. 移除所有 on* 事件屬性(onclick, onload, onerror...)
var regexEvents = new Regex(@"\son\w+\s*=", RegexOptions.IgnoreCase);
html = regexEvents.Replace(html, " _disabled_event=");
// 4. 移除 iframe 區塊
var regexIframe = new Regex(@"<iframe[\s\S]*?</iframe\s*>", RegexOptions.IgnoreCase);
html = regexIframe.Replace(html, "");
// 5. 移除 frameset 區塊
var regexFrameset = new Regex(@"<frameset[\s\S]*?</frameset\s*>", RegexOptions.IgnoreCase);
html = regexFrameset.Replace(html, "");
return html;
}
| 正則 | 說明 |
|---|---|
<script[\s\S]*?</script\s*> | [\s\S] 匹配任意字元含換行;*? 非貪婪匹配,避免吞併多組 script 標籤 |
\b(href|src|action)\s*=\s*[\s\S]*?\bjavascript\s*: | 針對屬性值中的 javascript:,\b 邊界確保不誤傷含 javascript 字串的正常內容 |
\son\w+\s*= | 匹配 on 開頭的事件屬性,替換為無害字串保留標籤結構 |
正則過濾屬於「黑名單」機制,難以覆蓋所有變形攻擊(如編碼繞過、CSS expression、SVG onload 等)。生產環境強烈建議採用「白名單」HTML 淨化庫:
// 安裝:Install-Package HtmlSanitizer
using Ganss.XSS;
var sanitizer = new HtmlSanitizer();
// 預設僅允許安全標籤:b, i, u, p, br, ul, ol, li, a[href], img[src] 等
string safeHtml = sanitizer.Sanitize(userInput);
// 自訂允許標籤/屬性
sanitizer.AllowedTags.Add("table");
sanitizer.AllowedAttributes.Add("class");
sanitizer.AllowedCssClasses.Add("text-red");
即使輸入端已過濾,輸出到 HTML 內容、屬性、JavaScript、URL、CSS 不同語境時,仍必須進行語境編碼:
// Razor 視圖中自動 HTML 編碼
@Model.UserContent
// 手動編碼(WebForms / 非 Razor)
HttpUtility.HtmlEncode(userInput) // HTML 內容
HttpUtility.HtmlAttributeEncode(userInput) // HTML 屬性值
HttpUtility.JavaScriptStringEncode(userInput) // JS 字串
HttpUtility.UrlEncode(userInput) // URL 參數
Content-Security-Policy 限制腳本來源、X-Content-Type-Options: nosniff、X-Frame-Options: DENYHttpOnly、Secure、SameSite=Strict/Lax本文提供的正則方案可作為快速原型或舊系統最小改動修補,但不建議作為生產環境唯一防線。現代 Web 應用應採用 HtmlSanitizer 等成熟白名單庫,配合 CSP、輸出編碼、安全標頭構建纵深防禦體系。