首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 正則過濾 HTML 標籤、屬性與 XSS 防護完整指南

     編輯:PHP 綜合知識

前言:為什麼需要過濾 HTML?

在處理用戶提交的富文本內容(評論、文章、聊天訊息)時,若直接輸出未經過濾的 HTML,極易導致 XSS (跨站腳本攻擊)、排版破壞、惡意腳本注入等安全風險。本文整理了 PHP 中使用正則表達式過濾 HTML 標籤、屬性、危險腳本的實用模式,並對比原生函數與現代最佳實踐。

核心正則模式庫(可直接複製使用)

1. 基礎清理:多餘空白、註解、DOCTYPE

$str = preg_replace('/\s+/', ' ', $str);                    // 合併多餘空白字符(含換行)
$str = preg_replace('/<[ ]+/si', '<', $str);              // 移除標籤左尖括號後的空格
$str = preg_replace('/<!--.*?-->/si', '', $str);         // 移除 HTML 註解
$str = preg_replace('/<(!.*?)>/si', '', $str);            // 移除 DOCTYPE 宣告

2. 移除特定結構性標籤(head、meta、body、link、form 等)

$patterns = [
    '/<(\/?html.*?)>/si',
    '/<(\/?head.*?)>/si',
    '/<(\/?meta.*?)>/si',
    '/<(\/?body.*?)>/si',
    '/<(\/?link.*?)>/si',
    '/<(\/?form.*?)>/si',
];
$str = preg_replace($patterns, '', $str);

3. 移除高風險互動標籤與屬性(XSS 核心防護)

// 移除完整標籤對(含內容):script, style, iframe, object, applet, frameset, title
$dangerous_tags = ['script', 'style', 'iframe', 'object', 'applet', 'frameset', 'title', 'noscript'];
foreach ($dangerous_tags as $tag) {
    $str = preg_replace("/<($tag.*?)>(.*?)<(\/$tag.*?)>/si", '', $str); // 含內容
    $str = preg_replace("/<(\/?$tag.*?)>/si", '', $str);                   // 殘留單標籤
}

// 移除事件屬性:onclick, onload, onerror, onmouseover 等
$str = preg_replace('/\s(on[a-z]+)\s*=/si', ' data-\\1=', $str); // 改為 data-* 屬性失效化

// 移除 javascript:、vbscript: 協議
$str = preg_replace('/javascript:/si', 'javascript:', $str); // 大小寫混淆繞過
$str = preg_replace('/vbscript:/si', 'vbscript:', $str);

// 實體編碼攔截
$str = preg_replace('/&#/si', '&#', $str);

4. 保留安全標籤的白名單過濾(推薦策略)

黑名單永遠不完整,白名單才是正道。 只允許 p, br, strong, em, u, span, div, img, a, ul, ol, li, blockquote, code, pre, h1-h6 等安全標籤:

function html_whitelist_filter($html, $allowed_tags = 'p,br,strong,em,u,span,div,img,a,ul,ol,li,blockquote,code,pre,h1,h2,h3,h4,h5,h6') {
    // 1. 先移除所有事件屬性與危險協議
    $html = preg_replace('/\s(on\w+)\s*=/i', ' data-\\1=', $html);
    $html = preg_replace('/(href|src)\s*=\s*["\']?\s*(javascript|vbscript|data):/i', '\\1="#blocked"', $html);
    
    // 2. 使用 strip_tags 保留白名單(注意:strip_tags 不檢查屬性安全性)
    $html = strip_tags($html, '<' . implode('><', explode(',', $allowed_tags)) . '>');
    
    // 3. 進一步清理保留標籤的危險屬性(需配合 DOMDocument 或 HTMLPurifier)
    return $html;
}

原生函數 vs 正則 vs 專業庫:深度對比

方案優點缺點適用場景
strip_tags() 內建、速度快、語法簡單 無法過濾屬性(如 onclick、style);允許標籤時屬性全保留;HTML5 新標籤支援有限 極簡場景、完全信任的內容
自訂正則 preg_replace 靈活、可精準控制、無依賴 正則難以完美解析巢狀/破損 HTML;效能隨內容增長下降;極易漏過繞過技巧(編碼、大小寫、換行混淆) 簡單過濾、特定格式清理、學習用途
HTMLPurifier (推薦) 標準合規、白名單機制、防禦所有已知 XSS、支援 HTML5、可配置極細緻 體積大、效能較低(可配合快取)、需 Composer 安裝 所有生產環境富文本處理
DOMDocument + XPath 正確解析 DOM 樹、可精準操作節點屬性、原生無依賴 對不合法 HTML 容錯差(需 libxml_use_internal_errors);API 複雜;大文件記憶體佔用高 結構化提取、特定屬性清理、不想引入重型庫

HTMLPurifier 快速上手(生產環境標準配置)

// Composer 安裝: composer require ezyang/htmlpurifier
require_once 'vendor/autoload.php';

$config = HTMLPurifier_Config::createDefault();
// 核心白名單設定
$config->set('HTML.Allowed', 'p,br,strong,em,u,span[style],div[style],img[src|alt|width|height],a[href|title|target],ul,ol,li,blockquote,code,pre,h1,h2,h3,h4,h5,h6');
// 允許的 CSS 樣式屬性(防止 CSS 注入)
$config->set('CSS.AllowedProperties', 'color,background-color,font-size,font-weight,text-align,text-decoration,margin,padding,border');
// 圖片限制同域或 HTTPS
$config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true]);
$config->set('Attr.EnableID', true); // 允許 id 屬性

$purifier = new HTMLPurifier($config);
$safe_html = $purifier->purify($dirty_html);

常見正則陷阱與繞過技巧(防禦視角)

  • 大小寫混淆: <ScRiPt> — 需加 i 修飾符
  • 編碼繞過: <img src=javascript:alert(1)> — 需先解碼實體再過濾
  • 屬性分隔符變體: <img/src='x'/onerror=alert(1)> — 正則難以全覆蓋
  • 巢狀標籤: <script><script>alert(1)</script></script> — 貪婪/非貪婪匹配失效
  • 條件編譯/IE 特有: <!--[if IE]><script>...</script><![endif]-->

結論:手寫正則無法覆蓋所有邊界情況,生產環境務必使用 HTMLPurifier。

輔助工具推薦

總結

  1. 簡單場景可用 strip_tags + 基礎正則清理屬性。
  2. 複雜富文本、用戶生成內容(UGC)**必須使用 HTMLPurifier**。
  3. 儲存時「輸入過濾」+ 輸出時「語境編碼」(HTML 實體編碼、JS 編碼、URL 編碼)雙重防護。
  4. 建立內容安全策略(CSP)作為最後一道防線:Content-Security-Policy: script-src 'self'; object-src 'none';
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved