提供三個針對不同語境的字元替換函式,分別處理**資料庫讀出顯示**、**寫入前過濾**、**單引號專用跳脫**,雖屬黑名單替換策略,可作為舊系統快速加固參考。
<?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_replace | SQL 字串拼接 | 單引號實體化 | 極高 |
')存入資料庫,**資料庫層面並不認得 HTML 實體**,SQL 引擎仍視為單引號,注入風險依然存在。;、--、/*、0x(十六進制)、CHAR() 等繞過手法。str_replace。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('參數錯誤');