首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 注入防禦實戰:從原理到纵深防御的三步走策略

     編輯:關於SqlServer

SQL 注入本質:數據與代碼邊界模糊

應用將不可信輸入直接拼接進 SQL 語句,導致數據庫將輸入視為代碼執行。攻擊者可繞過認證、竊取數據、提權、甚至通過 xp_cmdshell 獲取系統控制權。

三步走纵深防御體系

第一步:參數化查詢—— 根治拼接漏洞

原則:代碼與數據分離,數據庫預編譯計劃,參數僅作數據傳遞,永不參與語法解析。

覆蓋範圍:所有動態 SQL 構建點,包括 WHERE、ORDER BY、IN 列表、LIKE 模糊匹配、存儲過程動態 SQL(sp_executesql 參數化)。

第二步:最小權限與攻擊面縮減—— 限制損害半徑

  1. 數據庫賬號分級:Web 應用僅用 db_datareader/db_datawriter + 執行存儲過程權限,禁止 sysadmin、db_owner、BACKUP、xp_cmdshell。
  2. 禁用/移除危險擴展:sp_configure 'xp_cmdshell', 0; RECONFIGURE;、Ole Automation Procedures、Ad Hoc Distributed Queries。
  3. 錯誤信息不外泄:生產環境關閉詳細錯誤頁面,統一返回友好提示,日誌記錄完整堆棧供內部排查。
  4. 輸入長度/格式限制:前後端雙重驗證,如用戶名僅允許字母數字下劃線 20 字符,拒絕超長/特殊字符輸入。

第三步:主動檢測與運行時防護—— 捕獲殘留風險

  • WAF (Web Application Firewall):部署 ModSecurity + OWASP CRS 規則集,攔截含 UNION SELECT、OR 1=1、WAITFOR DELAY、0x 十六進制等特徵的請求。
  • SQL Server 審計/擴展事件:記錄失敗登錄、權限提升、動態 SQL 執行、大量錯誤返回等異常模式。
  • 自動化掃描:CI/CD 流水線集成 SAST(代碼靜態分析)、DAST(動態掃描)、IAST(交互式掃描),發布前強制門禁。
  • 蜜罐賬號/欺騙技術:創建高權限誘餌賬號,觸發即告警,延緩攻擊者偵察節奏(文中提到的「大字段誘餌」屬此類,但不建議作為主要防線,易被智能掃描器識別)。

進階防禦:存儲過程封裝 + 動態 SQL 安全模式


CREATE PROC dbo.usp_GetUserByName
    @Name NVARCHAR(50)
WITH EXECUTE AS CALLER  -- 權限上下文控制
AS
BEGIN
    SET NOCOUNT ON;
    -- 參數化動態 SQL(即使在存儲過程內也要參數化!)
    DECLARE @Sql NVARCHAR(MAX) = N'SELECT Id, Name, Email FROM dbo.Users WHERE Name = @Name';
    EXEC sp_executesql @Sql, N'@Name NVARCHAR(50)', @Name = @Name;
END

應急響應清單

  1. 發現注入 → 立即封禁攻擊源 IP、撤銷受影響賬號權限。
  2. 審計日誌回溯 → 確定數據洩露範圍、是否植入 Webshell/後門。
  3. 修復代碼 → 參數化所有動態 SQL、補丁部署。
  4. 通報合規部門 → 評估 GDPR/個信法報告義務。
  5. 全量掃描 → 排查同類漏洞、更新 WAF 規則。

SQL 注入防禦沒有銀彈,參數化查詢是根基,最小權限是護盾,持續監控是利劍。將三步走策略內化為團隊開發規範、代碼評審清單、CI/CD 門禁標準,才能在源頭斬斷注入攻擊鏈。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
語言/框架錯誤寫法(拼接)正確寫法(參數化)
C# / ADO.NETcmd.CommandText = "SELECT * FROM Users WHERE Name = '" + name + "'";cmd.CommandText = "SELECT * FROM Users WHERE Name = @Name"; cmd.Parameters.AddWithValue("@Name", name);
Java / JDBCstmt.executeQuery("SELECT * FROM Users WHERE Name = '" + name + "'");ps = conn.prepareStatement("SELECT * FROM Users WHERE Name = ?"); ps.setString(1, name);
Python / pyodbccursor.execute(f"SELECT * FROM Users WHERE Name = '{name}'")cursor.execute("SELECT * FROM Users WHERE Name = ?", name)
PHP / PDO$pdo->query("SELECT * FROM Users WHERE Name = '$name'");$stmt = $pdo->prepare("SELECT * FROM Users WHERE Name = ?"); $stmt->execute([$name]);
Node.js / mssqlawait pool.query(`SELECT * FROM Users WHERE Name = '${name}'`)await pool.request().input('name', sql.NVarChar, name).query('SELECT * FROM Users WHERE Name = @name')