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

PHP HTML 字符串過濾與 XSS 防護函數大全

     編輯:PHP 相關知識

處理用戶提交的富文本、評論、文章內容時,需要過濾 HTML 標籤、轉義實體、防範 XSS 攻擊。本文匯總 PHP 內置函數與自定義過濾方案,涵蓋標籤剝離、實體轉義、SQL 注入防護等實用場景。

一、PHP 內置核心函數

1. strip_tags() —— 剝離 HTML/PHP 標籤

<?php
$html = '<p>內容</p><script>alert(1)</script><b>粗體</b>';

// 剝離所有標籤
echo strip_tags($html); 
// 輸出: 內容alert(1)粗體

// 保留允許的標籤(如 <p>、<b>、<img>)
echo strip_tags($html, '<p><b><img>');
// 輸出: <p>內容</p>alert(1)<b>粗體</b>
?>
  • 注意: strip_tags() 不屬性過濾,<img src=x onerror=alert(1)> 會保留危險屬性,不可單獨用於 XSS 防護。
  • 第二個參數為允許標籤列表,格式:'<p><a>'(無空格、無屬性)。

2. htmlspecialchars() —— 轉義 HTML 實體(XSS 核心防護)

<?php
$input = '<script>alert(1)</script>';
echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
// 輸出: &lt;script&gt;alert(1)&lt;/script&gt;
?>
  • 必用參數: ENT_QUOTES 轉義單雙引號,'UTF-8' 指定編碼。
  • 適用於輸出到 HTML 內容、屬性值、URL 參數等上下文。

3. htmlentities() —— 轉義所有實體

將所有可轉義字符轉為實體(含中文),體積膨脹大,一般不推薦,優先用 htmlspecialchars()。

二、自定義深度過濾函數(原文 StripHTML 改進版)

<?php
/**
 * 深度過濾 HTML:移除腳本/樣式、剝離標籤、轉義實體、規範空白
 * @param string $string
 * @return string
 */
function strip_html_deep($string) {
    if (!is_string($string)) return '';
    
    // 1. 移除 script/style 標籤及內容
    $string = preg_replace('/<(script|style)[^>]*>.*?<\/\1>/is', '', $string);
    
    // 2. 移除 HTML 註釋
    $string = preg_replace('/<!--.*?-->/s', '', $string);
    
    // 3. 剝離所有標籤(保留文本)
    $string = strip_tags($string);
    
    // 4. 轉義 HTML 實體(防殘留尖括號)
    $string = htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
    
    // 5. 規範空白字符:換行/制表/多空格 → 單空格
    $string = preg_replace('/\s+/u', ' ', $string);
    
    // 6. 去首尾空白
    return trim($string);
}

// 測試
$dirty = "<div>Hello<script>alert(1)</script> <b>World</b></div>";
echo strip_html_deep($dirty); // Hello World
?>

三、針對性過濾場景

1. 只保留安全標籤與屬性(富文本編輯器輸出)

使用 HTMLPurifier 庫(業界標準),而非自寫正則:

<?php
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title],img[src|alt|width|height],br,ul,ol,li');
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
?>

2. 防 SQL 注入(已過時,現代框架用預處理)

原文提供的 stripslashes_array 和 lib_replace_end_tag 屬於早期「過濾法」防注入,**現代最佳實踐是參數化查詢(Prepared Statements)**:

<?php
// PDO 預處理(防注入標準)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();

// MySQLi 預處理
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
?>

切勿使用字符串拼接 SQL,任何過濾函數都有繞過風險。

3. 輸出上下文編碼(Contextual Escaping)

輸出上下文編碼函數示例
HTML 文本內容htmlspecialchars($str, ENT_QUOTES, 'UTF-8')<div></div>
HTML 屬性值htmlspecialchars($str, ENT_QUOTES, 'UTF-8')<input value="">
URL 參數urlencode($str)<a href="?q=>
JavaScript 字符串json_encode($str)(含引號)<script>var x = ;</script>
CSS 值專用轉義庫避免直接內聯

四、常用工具函數封裝

<?php
// 通用 HTML 轉義助手
function h($str, $double_encode = true) {
    return htmlspecialchars((string)$str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', $double_encode);
}

// 只允許安全標籤的輸出(需 HTMLPurifier)
function safe_html($html, $config = null) {
    static $purifier = null;
    if ($purifier === null) {
        require_once 'HTMLPurifier.auto.php';
        $cfg = HTMLPurifier_Config::createDefault();
        $cfg->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title],img[src|alt],br,ul,ol,li,span[style],div[class]');
        $purifier = new HTMLPurifier($cfg);
    }
    return $purifier->purify($html);
}

// 移除所有標籤並獲取純文本
function plain_text($html) {
    return trim(preg_replace('/\s+/u', ' ', strip_tags($html)));
}
?>

總結:防護分層策略

  1. 輸入端: 長度限制、格式驗證(郵箱、手機、數字),**不做過度過濾**,保存原始數據。
  2. 存儲端: 使用預處理語句,防止 SQL 注入。
  3. 輸出端: 根據上下文嚴格編碼(h()、urlencode()、json_encode()),富文本用 HTMLPurifier 白名單過濾。
  4. 瀏覽器端: 設置 Content-Security-Policy (CSP) 頭,禁用內聯腳本,限制資源來源。

「過濾 HTML」不是單一函數能解決的,而是分層防護體系。棄用舊式「過濾法」防注入,擁抱預處理與上下文編碼,引入 HTMLPurifier 處理富文本,構建可維護的安全防線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved