經典 ' OR 1=1 -- 繞過登錄演示,對比 Statement(拼接 SQL)與 PreparedStatement(參數化查詢)對注入的防禦能力差異。
原始查詢:
SELECT * FROM users WHERE username='input_user' AND password='input_pass'
惡意輸入:
username: admin
password: ' OR 1=1 -- (注意 -- 後有空格)
拼接後 SQL:
SELECT * FROM users WHERE username='admin' AND password='' OR 1=1 -- '
-- 註釋掉後續單引號,1=1 恆真,直接登入。
| 維度 | Statement | PreparedStatement |
|---|---|---|
| SQL 構建 | 字符串拼接 | 預編譯 + 參數佔位符 ? |
| 上述注入 | ✅ 成功繞過 | ❌ 失敗(參數視為字面值) |
| 性能 | 每次解析編譯 | 預編譯一次,多次複用計劃 |
| 類型安全 | 無 | 強類型綁定 |
// Java 範例 String sql = "SELECT * FROM users WHERE username=? AND password=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); // 參數傳輸與 SQL 結構分離 ps.setString(2, password); ResultSet rs = ps.executeQuery();
數據庫引擎在預編譯階段確定執行計劃,參數永遠不會改變 SQL 結構,徹底杜絕注入。
SELECT/INSERT/UPDATE/DELETE,無 DROP/ALTERsqlmap、OWASP ZAP 自動化檢測sql_mode=STRICT_TRANS_TABLES,NO_AUTO_CREATE_USERPREPARE/EXECUTE)MariaDB Audit Plugin、MySQL Enterprise Audit