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

PHP 輸入驗證與過濾:從黑名單過濾到白名單驗證的正確姿勢

     編輯:PHP 相關知識

為什麼黑名單過濾不可靠?

嘗試列舉所有「危險字符」(單引號、分號、<script>、SQL 關鍵字等)屬於黑名單策略,存在三大缺陷:

  1. 繞過變體無窮:大小寫、編碼(URL/Unicode/雙重編碼)、註釋、空白字符插入等。
  2. 誤傷正常業務:用戶名 "O'Connor"、文章內容包含 "SELECT * FROM" 等合法輸入被截斷。
  3. 維護成本極高:需持續跟進新攻擊向量,且無法覆蓋所有上下文(HTML、SQL、JS、Shell、LDAP 等)。

核心原則:輸入驗證 ≠ 輸出編碼

  • 輸入驗證:確認資料符合業務預期格式(長度、型別、格式、範圍),拒絕不合法資料進入系統。
  • 輸出編碼:根據輸出上下文(HTML、JS、CSS、URL、SQL)對資料進行適當編碼,防止注入攻擊。

兩者缺一不可,且不可混淆。

PHP 內建驗證與過濾工具

1. filter_var() / filter_input() — 型別與格式驗證

$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]]);
$url = filter_var($input, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED);
$ip = filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);

2. 正則表達式 — 自訂格式驗證

// 手機號(台灣範例)
if (!preg_match('/^09\d{8}$/', $phone)) {
    throw new InvalidArgumentException('手機號格式錯誤');
}

// 中英文姓名,2-20 字元
if (!preg_match('/^[\p{Han}\p{L}\s\-\.]{2,20}$/u', $name)) {
    throw new InvalidArgumentException('姓名格式錯誤');
}

3. 白名單枚舉 — 固定選項驗證

$allowedStatus = ['pending', 'paid', 'shipped', 'cancelled'];
$status = $_POST['status'] ?? '';
if (!in_array($status, $allowedStatus, true)) {
    throw new InvalidArgumentException('無效狀態值');
}

上下文相關的輸出編碼

輸出上下文PHP 函數/方法範例
HTML 內容htmlspecialchars()echo htmlspecialchars($userInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
HTML 屬性htmlspecialchars()<input value="<?= htmlspecialchars($val, ENT_QUOTES, 'UTF-8') ?>">
JavaScript 字串json_encode()<script>var data = <?= json_encode($val, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;</script>
URL 參數rawurlencode()$url = 'search.php?q=' . rawurlencode($keyword);
SQL 查詢預處理語句$stmt->execute([$param]);(而非字串拼接)
Shell 指令escapeshellarg()exec('convert ' . escapeshellarg($input) . ' output.png');

實務架構建議

  1. 表單請求物件:封裝驗證邏輯於專屬類別(如 Laravel Form Request、Symfony Validator),控制器保持精簡。
  2. 統一異常處理:驗證失敗拋出 ValidationException,由全域處理器回傳結構化錯誤訊息。
  3. 模板引擎自動逃逸:使用 Twig、Blade、Lathe 等支援預設 HTML 逃逸的模板引擎,減少人為疏漏。
  4. 內容安全政策:部署 CSP 標頭作為最後防線,限制腳本來源、禁止內聯腳本。

結語

放棄「過濾危險字符」的黑名單思維,轉而採用白名單驗證輸入格式 + 上下文感知輸出編碼 + 預處理語句處理 SQL 的組合拳,才能從根本上解決 XSS、SQLi、指令注入等注入類漏洞。

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