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

PHP SQL 注入過濾:三階段字元替換與防護策略

     編輯:PHP 相關知識

PHP 防 SQL 注入字元過濾函式組

提供三個針對不同語境的字元替換函式,分別處理**資料庫讀出顯示**、**寫入前過濾**、**單引號專用跳脫**,雖屬黑名單替換策略,可作為舊系統快速加固參考。

三個核心函式

<?php
// 1. 讀出顯示:還原常見編碼實體
function phpsql_show($str) {
    $str = stripslashes($str);
    $str = str_replace('\', '', $str);   // 反斜線
    $str = str_replace('/', '/', $str);  // 斜線
    $str = str_replace(' ', ' ', $str);  // 空白
    $str = str_replace(',', ',', $str);  // 逗號
    return $str;
}

// 2. 寫入前過濾:將特殊字元轉為 HTML 實體編碼
function phpsql_post($str) {
    $str = stripslashes($str);
    $str = str_replace('|', '|', $str);   // 管線符
    $str = str_replace('<', '<', $str);   // 小於
    $str = str_replace('>', '>', $str);   // 大於
    $str = str_replace(' ', ' ', $str);
    $str = str_replace(' ', ' ', $str);    // 空白
    $str = str_replace('(', '(', $str);    // 左括號
    $str = str_replace(')', ')', $str);    // 右括號
    $str = str_replace('`', '`', $str);    // 反引號
    // $str = str_replace('\'', ''', $str); // 單引號(註解掉)
    $str = str_replace('"', '"', $str);    // 雙引號
    $str = str_replace(',', ',', $str);    // 逗號
    $str = str_replace('$', '$', $str);    // 美元符
    $str = str_replace('\\', '\', $str);   // 反斜線
    $str = str_replace('/', '/', $str);    // 斜線
    return $str;
}

// 3. 單引號專用跳脫
function phpsql_replace($str) {
    $str = stripslashes($str);
    $str = str_replace('\'', ''', $str);
    return $str;
}

策略分析與風險

函式用途策略類型風險等級
phpsql_show資料庫 → 畫面實體還原(白名單式)低
phpsql_post使用者輸入 → 資料庫黑名單字元實體化高
phpsql_replaceSQL 字串拼接單引號實體化極高

關鍵缺陷說明

  1. 語境錯誤:將字元轉為 HTML 實體(')存入資料庫,**資料庫層面並不認得 HTML 實體**,SQL 引擎仍視為單引號,注入風險依然存在。
  2. 不完整覆蓋:漏掉 ;、--、/*、0x(十六進制)、CHAR() 等繞過手法。
  3. 編碼繞過:攻擊者可送入 URL 編碼、Unicode、雙重編碼繞過 str_replace。
  4. 效能問題:多次 str_replace 遍歷字串,大量資料時效能差。

正確防注入鐵則

<?php
// 唯一正解:Prepared Statements(參數化查詢)
// PDO
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = ? AND status = ?');
$stmt->execute([$name, 1]);

// MySQLi
$stmt = $mysqli->prepare('SELECT * FROM users WHERE name = ? AND status = ?');
$stmt->bind_param('si', $name, $status);
$stmt->execute();

// 如必須拼接 SQL(極不建議),務必使用驅動程式提供的跳脫函式
$safe_name = $pdo->quote($name); // PDO::quote 包含引號
$sql = "SELECT * FROM users WHERE name = {$safe_name}";

舊系統快速修補建議

若無法立即重構為 Prepared Statements,可採用**白名單驗證**作為過渡:

<?php
function validate_input($value, $type) {
    switch ($type) {
        case 'int':    return filter_var($value, FILTER_VALIDATE_INT);
        case 'email':  return filter_var($value, FILTER_VALIDATE_EMAIL);
        case 'alpha':  return ctype_alpha($value) ? $value : false;
        case 'alnum':  return ctype_alnum($value) ? $value : false;
        default:       return false;
    }
}

// 使用
$user_id = validate_input($_GET['id'], 'int');
if ($user_id === false) die('參數錯誤');
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved