歡迎光臨
我們一直在努力

Microsoft SQL Server SQL Injection 特性與防禦

安全提醒:本文為防禦導向的虛構案例與不可部署片段;測試僅限自有或明確授權環境。

SQL Server 使用 T-SQL,常見於 .NET、企業內網與報表系統。批次語句、動態 SQL、stored procedure 與資料庫角色使風險形狀不同,但根因仍是把不可信資料組進命令文字。

SQL Server 安全資料存取技術流程圖
SQL Server 安全資料存取:依序追蹤資料與安全控制點。

本篇會學到什麼

  • 分辨 SqlCommand.Parameters 與字串插值
  • 理解 stored procedure 內動態 SQL 仍可能注入
  • 以明確 SqlDbType、長度與最小角色降低風險

必備名詞與心智模型

ADO.NET 參數會把輸入視為 literal 並提供型別資訊。sp_executesql 只有在動態 SQL 模板固定、值透過參數傳遞時才安全;若先把字串串好再交給它,名稱聽起來像參數化也不會補救。Stored procedure 也可能在內部 EXEC 拼接字串。

發生情境與生活化比喻

企業報表允許依部門、日期與欄位排序。開發者可能以為內網使用者可信,或認為 stored procedure 一定安全。實際上代理、批次匯入與報表參數仍會跨越信任邊界。

不安全的原始碼

var department = Request.Query["department"];
var sql = $"SELECT Id,Total FROM Orders WHERE Department='{department}'";
using var command = new SqlCommand(sql, connection);
using var reader = command.ExecuteReader();

此片段刻意省略連線、路由與部署設定,只用來辨識資料流,請勿放入任何服務。

逐步看懂資料如何變成查詢

  1. QueryString 進入 C# 字串插值
  2. SqlCommand 收到的 CommandText 已包含外部資料
  3. SQL Server 解析 T-SQL 批次
  4. stored procedure 若再拼接輸入會重複相同問題
  5. db_owner 等過大角色使注入後果擴大

修補後原始碼

const string sql = "SELECT Id,Total FROM Orders WHERE Department=@department";
using var command = new SqlCommand(sql, connection);
command.Parameters.Add("@department", SqlDbType.NVarChar, 80).Value = department;
using var reader = command.ExecuteReader();

修補的共同原則是先固定 SQL 結構,再把值獨立綁定;無法作為值綁定的識別字只能從程式內允許清單產生。

如何驗證修補

  • 不用 AddWithValue 猜測關鍵欄位型別與長度
  • 檢查 stored procedure 內 EXEC/EXECUTE 與動態 SQL
  • 合法撇號與 Unicode 部門名不造成錯誤
  • 應用登入不屬於 sysadmin 或 db_owner
  • SQL Audit/Extended Events 對異常錯誤有適當告警


閱讀提醒:以下分析的目的,是讓你能在自己的程式、測試資料與授權環境中辨識風險。面對正式系統時,先取得明確授權並保存變更紀錄;不要用錯誤訊息或一次回應就推論資料外洩,也不要把文章中的概念改造成自動化探測。安全工作的完成條件,是能說明根因、修補位置、回歸結果與剩餘風險。

更多應用情境、常見誤判與觀察方法

把原理放回真實開發情境

SQL Server 使用具型別參數;動態需求由 sp_executesql 搭配參數,識別字則由固定映射控制。 實作時不要只盯著畫面上的輸入框,還要檢查 API 參數、伺服器端預設值、資料轉換與最後呼叫的資料庫介面。最實用的閱讀方式,是把每一段程式標成「外部來源、轉換、控制、資料庫 sink」,確認資料值沒有在途中重新變回 SQL 結構。

常見誤判

Stored Procedure 內若仍 EXEC 拼接字串,並不會因為『用了預存程序』就安全。 安全判斷不能只靠畫面、單次錯誤或某一個防護產品;應同時看原始碼、驅動程式實際執行方式、資料庫權限與回歸測試。若無法證明查詢結構固定,就應把它視為待修的設計風險。

開發與 SOC 可以觀察什麼

稽核高權限角色、異常批次形狀、轉型錯誤與應用帳號的非預期物件存取。 日誌宜記錄時間、路由、請求關聯 ID、查詢名稱、結果狀態與耗時,敏感值則遮罩或雜湊。偵測規則的用途是縮短發現時間;阻擋之後仍須回到程式碼修補,並搜尋其他共用元件與相同資料流。

審查時的三個追問

  1. 這個值最早由誰控制,經過哪些轉換?
  2. 它在資料庫呼叫中是資料值,還是欄位、排序、運算式等結構?
  3. 若預防失效,最小權限、監控與事件流程能限制並發現多少影響?

開發與維運防禦清單

  • 所有值使用 SqlParameter 或安全 ORM 參數
  • 動態識別字映射固定清單
  • sp_executesql 的 statement 與 parameter definition 分離
  • 限制跨資料庫權限、linked server 與高權限 service account

重點整理與下一篇

下一篇轉向 PostgreSQL,說明 $1 參數、PQexecParams、單一命令限制、明確型別轉換與 schema/search_path 的安全考量。

參考資料與更新日期

更新日期:2026-07-20

贊(0) 贊助
未經允許不得轉載:波波的寂寞世界 » Microsoft SQL Server SQL Injection 特性與防禦

波波的寂寞世界

Facebook聯繫我們

覺得文章有幫助,歡迎贊助支持本站

感謝你的支持,我會持續整理資安筆記、實務經驗與有價值的技術內容。

贊助本站