SQL注入仍是 Web 應用頭號安全威脅。本文從原理、攻擊步驟、實戰演示到防範體系,構建完整知識體系。

CREATE TABLE `postmessage` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`subject` varchar(60) NOT NULL DEFAULT '',
`name` varchar(40) NOT NULL DEFAULT '',
`email` varchar(25) NOT NULL DEFAULT '',
`question` mediumtext NOT NULL,
`postdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312 COMMENT='用戶留言';
<?php
// show.php
$id = $_GET['id']; // 無任何過濾!
$sql = "SELECT * FROM postmessage WHERE id = $id";
$result = mysql_query($sql);
// ...
?>
# 正常請求
https://example.com/show.php?id=71
# 永真條件測試
https://example.com/show.php?id=71 and 1=1
# 返回正常 → 存在注入點
# 永假條件測試
https://example.com/show.php?id=71 and 1=2
# 返回空/報錯 → 確認注入
# 聯集注入探測字段數
https://example.com/show.php?id=71 UNION SELECT 1,2,3,4,5,6
<?php
// PDO 範例
$stmt = $pdo->prepare("SELECT * FROM postmessage WHERE id = ?");
$stmt->execute([$_GET['id']]);
$data = $stmt->fetch();
// MySQLi 範例
$stmt = $mysqli->prepare("SELECT * FROM postmessage WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
?>
原理:SQL 模板與數據分離傳輸,數據庫引擎解析模板時不會將數據視為 SQL 片段。
$id = (int)$_GET['id']; // 強制整型
if (!ctype_digit($_GET['id'])) exit('非法參數');
SELECT/INSERT/UPDATE 權限,禁止 DROP/ALTER/FILELOAD DATA INFILE、INTO OUTFILEini_set('display_errors', 0);
error_reporting(E_ALL & ~E_NOTICE);
// 生產環境記錄日誌而非顯示
SQL注入本質是代碼與數據未分離。參數化查詢是銀彈,配合最小權限、錯誤隱藏、審計監控構建纵深防御體系。永遠不要信任任何外部輸入,是安全開發的鐵律。