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

PHP 防 SQL 注入過濾類:全局 GPC 過濾與類型化驗證

     編輯:PHP 綜合知識

防注入多層防禦體系

本類提供三層防護:全局 GPC 過濾(入口統一轉義)、類型化檢查函數(整數/字串/搜尋關鍵字)、SQL 關鍵字黑名單(二次攔截)。

核心代碼 (common_filter.php)

<?php
// === 1. 全局 GPC 過濾(放在入口文件最前面 require_once) ===
if (@get_magic_quotes_gpc()) {
    $_GET    = _deepAddSlashes($_GET);
    $_POST   = _deepAddSlashes($_POST);
    $_COOKIE = _deepAddSlashes($_COOKIE);
    $_FILES  = _deepAddSlashes($_FILES);
}
$_SERVER = _deepAddSlashes($_SERVER);

function _deepAddSlashes(&$val) {
    if (is_array($val)) {
        foreach ($val as $k => $v) $val[$k] = _deepAddSlashes($v);
    } elseif (is_string($val)) {
        $val = addslashes($val);
    } elseif (is_numeric($val)) {
        $val = intval($val);
    }
    return $val;
}

// === 2. 類型化驗證函數 ===
// 整數參數(ID、頁碼等)
function intCheck($val, $min = null, $max = null) {
    if ($val === '' || $val === null) die('參數不能為空');
    if (!ctype_digit((string)$val)) die('非法參數:非純數字');
    $val = intval($val);
    if ($min !== null && $val < $min) die("參數不能小於 $min");
    if ($max !== null && $val > $max) die("參數不能大於 $max");
    return $val;
}

// 字串參數(標題、內容等)
function strCheck($val, $maxLen = 255) {
    if (injectCheck($val)) die('非法參數:疑似 SQL 注入');
    $val = htmlspecialchars($val, ENT_QUOTES, 'UTF-8');
    if (strlen($val) > $maxLen) die("內容過長,最多 $maxLen 字符");
    return $val;
}

// 搜尋關鍵字(需保留 % _ 通配符)
function searchCheck($val) {
    if (injectCheck($val)) die('非法參數');
    $val = str_replace(['_', '%'], ['\_', '\%'], $val);
    return htmlspecialchars($val, ENT_QUOTES, 'UTF-8');
}

// 表單提交綜合檢查
function postCheck($val, $min = 0, $max = 65535) {
    $len = strlen($val);
    if ($len < $min) die("最少 $min 字節");
    if ($len > $max) die("最多 $max 字節");
    return stripslashesDeep($val); // 還原 addslashes
}

function stripslashesDeep(&$val) {
    if (is_array($val)) foreach ($val as $k => $v) $val[$k] = stripslashesDeep($v);
    elseif (is_string($val)) $val = stripslashes($val);
    return $val;
}

// === 3. SQL 注入特徵黑名單 ===
function injectCheck($str) {
    // 僅作二次攔截,不能替代預處理!
    $pattern = '/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i';
    return preg_match($pattern, $str) === 1;
}
?>

使用示例

<?php
require_once 'common_filter.php';

// 列表頁:page 必須是正整數
$page = intCheck($_GET['page'] ?? 1, 1, 10000);

// 文章詳情:id 整數
$id = intCheck($_GET['id']);

// 搜尋:關鍵字保留通配符
$kw = searchCheck($_GET['kw'] ?? '');

// 發布文章:標題、內容
$title   = strCheck($_POST['title'], 100);
$content = strCheck($_POST['content'], 65535);

// 入庫時使用 PDO 預處理(終極防線)
$stmt = $pdo->prepare("INSERT INTO article (title, content) VALUES (?, ?)");
$stmt->execute([$title, $content]);
?>

關鍵原則與現代最佳實踐

  1. 棄用 addslashes / mysql_real_escape_string:不完整、易繞過、PHP 7+ 已移除。
  2. 唯一標準:PDO / mysqli 預處理語句:參數與 SQL 徹底分離,從根源消除注入。
  3. 輸入驗證 ≠ 輸出轉義:
    • 入庫前:驗證類型、長度、格式(白名單)。
    • 輸出 HTML:htmlspecialchars($str, ENT_QUOTES, 'UTF-8') 防 XSS。
    • 輸出 JS/JSON:json_encode。
    • 輸出 Shell:escapeshellarg。
  4. 黑名單只是輔助:injectCheck 只能攔截明顯攻擊,無法防禦編碼繞過、二次注入等。
  5. 最小權限原則:資料庫帳號僅授予必要權限(SELECT/INSERT/UPDATE),禁用 DROP、FILE、SHUTDOWN 等。

快速遷移清單(舊專案升級)

  • [ ] 所有 mysql_query($sql) 改為 $pdo->prepare()->execute()
  • [ ] 移除全局 addslashes,改用類型化驗證函數
  • [ ] 所有輸出點加上 htmlspecialchars
  • [ ] 資料庫帳號降權
  • [ ] 開啟 WAF / 開啟 MySQL sql_mode=STRICT_TRANS_TABLES
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved