萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

防範 SQL 注入攻擊:參數化查詢、存儲過程、ORM 實戰防禦指南

SQL 注入本質是「資料被當成指令執行」。核心防禦原則:**永遠不拼接 SQL 字串,改用參數化查詢**。

經典注入示範

-- 應用拼接
sql = "SELECT * FROM users WHERE name='" + txtName.Text + "' AND pwd='" + txtPwd.Text + "'";

-- 攻擊輸入:txtName = "admin' --"
-- 實際執行:SELECT * FROM users WHERE name='admin' --' AND pwd='...'
-- 註解掉密碼檢查,直接以 admin 登入

防禦層級 (由強到弱)

Level 1:參數化查詢 / Prepared Statement (首選)

-- C# ADO.NET
string sql = "SELECT * FROM users WHERE username=@user AND password=@pwd";
using (var cmd = new SqlCommand(sql, conn)) {
    cmd.Parameters.AddWithValue("@user", txtName.Text);
    cmd.Parameters.AddWithValue("@pwd", txtPwd.Text);
    // 參數在引擎層綁定,永遠不會被解析為 SQL 指令
}

-- Java JDBC
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE username=? AND password=?");
ps.setString(1, name); ps.setString(2, pwd);

-- PHP PDO
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->execute([$name, $pwd]);

Level 2:存儲過程 (參數同樣強類型綁定)

CREATE PROC sp_login @user NVARCHAR(50), @pwd NVARCHAR(50)
AS SELECT * FROM users WHERE username=@user AND password=@pwd;
-- 應用呼叫 EXEC sp_login @user, @pwd

Level 3:ORM / Query Builder (框架層面自動參數化)

  • Entity Framework / Dapper / Hibernate / MyBatis / Laravel Eloquent / ThinkPHP Db::table() 皆內建參數化。
  • 避免使用 WhereRaw、DB::raw 等繞過機制。

Level 4:輸入驗證與清洗 (輔助、不可單獨依賴)

  • 白名單驗證:Regex.IsMatch(input, "^[a-zA-Z0-9_]{3,20}$")。
  • 長度限制:MaxLength、StringLength 屬性。
  • 轉義函數 (最後防線) mysqli_real_escape_string / PDO::quote,但易漏、不支援所有語境。

進階防護

  • 最小權限原則:應用布號僅擁有必要表的 SELECT/INSERT/UPDATE/DELETE,無 DDL/DROP 權限。
  • WAF / RASP:雲防火牆、OpenRASP 運行時檢測異常 SQL 模式。
  • 審計日誌:記錄所有失敗登入、DDL、大量刪除操作,配合 SIEM 告警。
  • 錯誤訊息不外露:生產環境關閉詳細 SQL 錯誤回顯,統一回傳「系統錯誤」。

常見誤區

誤區真相
「我過濾了單引號就安全」編碼繞過、二次注入、數值型注入 (id=1 OR 1=1) 完全繞過
「存儲過程絕對安全」存儲過程內部若用動態 SQL 拼接 (EXEC @sql) 同樣可被注入
「只有 Web 表單會被注入」API、爬蟲回調、日誌解析、ETL 匯入、內部工具皆為入口

將「參數化查詢」寫入團隊編碼規範、Code Review 必檢項、CI 掃描規則 (SonarQube/Semgrep),從源頭杜絕 SQL 注入。

copyright © 萬盛學電腦網 all rights reserved