本文旨在**防禦教育**,展示攻擊原理以便開發者理解風險並建立防護。**嚴禁**將此資訊用於未授權系統測試或攻擊。所有程式碼範例已去武器化,僅保留教學骨架。
原始碼片段 (PHP + MySQL) 展示兩個模組的脆弱模式:
$where = "where uname != 'Anonymous' ";
if ($letter != "Other" && $letter != "All") {
$where .= "AND uname LIKE '" . $letter . "%' "; // 直接拼接使用者輸入
}
$sort = "ORDER BY $sortby"; // 欄位名同樣拼接
$limit = " ASC LIMIT $min, $max"; // 數值參數未驗證
$result = sql_query($select . $where . $sort . $limit, $dbi);
攻擊向量:letter、sortby、min/max 皆可注入。若 magic_quotes_gpc=OFF,單引號不被轉義,攻擊者可構造:
letter = ' OR '1'='1 → 繞過過濾,列出所有用戶。sortby = UserID; DROP TABLE users; -- → 多語句執行 (視驅動程式支援)。min = 0; UPDATE users SET pass='hacked' WHERE uid=1; -- → 資料竄改。
case "login":
login($uname, $pass); // 內部可能直接拼接
function login($uname, $pass) {
$sql = "SELECT * FROM users WHERE uname='$uname' AND pass='$pass'";
}
經典繞過:uname = ' OR '1'='1' --、pass = anything → 以第一個用戶身分登入 (通常為管理員)。
所有範例共同點:**使用者輸入直接拼接至 SQL 字串**,導致資料庫將輸入視為指令而非資料。防御核心原則:**永遠使用參數化查詢 / 預備陳述式**。
| 平台 | 正確寫法 | 錯誤寫法 |
|---|---|---|
| PHP (PDO) | $stmt = $pdo->prepare("SELECT * FROM users WHERE uname = ?"); $stmt->execute([$uname]); | "SELECT * FROM users WHERE uname = '$uname'" |
| PHP (mysqli) | $stmt = $mysqli->prepare("SELECT * FROM users WHERE uname = ?"); $stmt->bind_param("s", $uname); | 同左 |
| ASP.NET (ADO.NET) | cmd.CommandText = "SELECT * FROM Users WHERE UserName = @u"; cmd.Parameters.AddWithValue("@u", userName); | "SELECT * FROM Users WHERE UserName = '" + userName + "'" |
| Java (JDBC) | PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE uname = ?"); ps.setString(1, uname); | Statement stmt = conn.createStatement(); "SELECT * FROM users WHERE uname = '" + uname + "'" |
| SQL Server (T-SQL) | EXEC sp_executesql N'SELECT * FROM Users WHERE UserName = @u', N'@u nvarchar(50)', @u = @UserName; | EXEC('SELECT * FROM Users WHERE UserName = ''' + @UserName + '''') |
| Python (DB-API) | cur.execute("SELECT * FROM users WHERE uname = %s", (uname,)) | cur.execute("SELECT * FROM users WHERE uname = '" + uname + "'") |
SELECT/INSERT/UPDATE/DELETE 特定表權限,無 DROP/ALTER/xp_cmdshell。sortby 必須在白名單中 (['UserID','CreateDate','LastLogin']);分頁參數 min/max 強制轉型 int 並檢查範圍。EXEC usp_GetUsers @Country。SQL Server Audit / Extended Events 記錄失敗登入、權限變更、大量資料異動、動態 SQL 執行。| 誤區 | 真相 |
|---|---|
| 「我用 stored procedure 就安全」 | 若 SP 內部仍用字串拼接 EXEC('SELECT * FROM T WHERE C = ' + @v),同樣可注入。 |
| 「我過濾單引號就夠了」 | 編碼繞過、二次注入、數值型注入 (無需引號)、寬字元注入均可繞過。 |
| 「ORM (EF/Hibernate) 自動防注入」 | ORM 參數化 LINQ/HQL 安全,但 FromSqlRaw/CreateSQLQuery 仍可拼接,需代碼審查。 |
| 「內部系統不需防注入」 | 內部威脅、橫向移動、供應鏈攻擊同樣利用注入。零信任原則:所有輸入皆視為不信任。 |
[ ] 所有 SQL 使用參數化查詢 / 預備陳述式
[ ] 動態排序/分頁/欄位名採白名單驗證
[ ] 資料庫帳號最小權限、移除危險擴展預存程序
[ ] 錯誤訊息不回傳前端、啟用審計日誌
[ ] CI/CD 整合 SAST 掃描 SQL 拼接模式
[ ] 定期滲透測試、WAF 規則更新