SQL 注入與防禦實戰:MySQL 中 HAVING 1=1 技巧失效分析
某安全書籍介紹利用 HAVING 1=1 觸發錯誤回顯獲取資訊,但在 MySQL 5.1.66 實測中該技巧失效。本文分析原因,並探討 MySQL 中構造必報錯語句的函數組合。
一、書籍所述技巧
-- SQL Server 環境
SELECT * FROM table WHERE id=2 HAVING 1=1;
-- 報錯:缺少 GROUP BY,錯誤訊息可能洩露結構資訊
二、 MySQL 實測結果
mysql> SELECT * FROM aa WHERE id=2 HAVING 1=1;
+----+------+
| id | name |
+----+------+
| 2 | test |
+----+------+
1 row in set (0.00 sec)
-- 正常返回結果,無報錯
三、差異根因
| 特性 | SQL Server | MySQL |
| HAVING 無 GROUP BY | 語法錯誤,拋出異常 | 合法,視為全表單一分組,等同 WHERE |
| 錯誤回顯 | 可利用獲取元數據 | 此處不產生錯誤 |
MySQL 允許 HAVING 無 GROUP BY,將整個結果集視為一組進行過濾,語義等同 WHERE。
四、MySQL 中構造必報錯語句的函數組合
要觸發 MySQL 語法/運行時錯誤,需利用「強制同時存在」的語法結構:
- 聚合函數與非聚合列混用且無 GROUP BY:
SELECT id, COUNT(*) FROM aa; -- ERROR 1140: Mixing of GROUP columns
- 子查詢返回多行用於單值上下文:
SELECT * FROM aa WHERE id = (SELECT id FROM aa); -- ERROR 1242: Subquery returns more than 1 row
- 類型轉換失敗:
SELECT 'abc' + 1; -- 警告 Truncated, 不報錯
SELECT CAST('abc' AS UNSIGNED); -- 返回 0, 不報錯
- 除零錯誤 (需 sql_mode):
SET SESSION sql_mode='ERROR_FOR_DIVISION_BY_ZERO';
SELECT 1/0; -- ERROR 1365: Division by 0
- 函數參數類型/數量錯誤:
SELECT DATE_FORMAT(NOW()); -- ERROR 1582: Incorrect parameter count
五、防禦體系建設 (重點)
- 參數化查詢 / 預處理語句:根治注入,
PreparedStatement、PDO::prepare
- 最小權限帳號:應用帳號僅擁有必要增刪改查權限,無 DDL/DCL 權限
- 錯誤訊息不回顯給前端:生產環境關閉
display_errors,統一友好提示
- WAF/IDS:ModSecurity + OWASP CRS 規則集攔截常見攻擊載荷
- 審計日誌:MariaDB Audit Plugin / MySQL Enterprise Audit 記錄所有 DML/DDL
- 定期掃描:sqlmap、OWASP ZAP 自動化掃描驗證防禦有效性
六、總結
不同資料庫對 SQL 標準的實現細節差異巨大,攻擊技巧極強相關性。防禦不應依賴「攻擊失效」,而應建立「參數化查詢 + 最小權限 + 錯誤隱藏 + 審計監控」的纵深防禦體系。
- 上一篇文章: MySQL 關鍵效能指標 QPS/TPS 計算與監控實戰
- 下一篇文章: MySQL GTID 主從復制完整配置指南
Copyright ©
程式碼之家 All Rights Reserved