跳過到頁腳內容
Iron Academy Logo
C#資料庫整合

什麼是SQL注入,如何在C#中預防?

Tim Corey
34m 33s

SQL注入是一種程式碼注入技術,允許攻擊者通過使用者輸入將惡意SQL程式碼發送到您的資料庫伺服器。 在他的影片"什麼是SQL注入以及如何在C#中防止它?"中,Tim Corey 精確演示了SQL注入漏洞如何出現在真實程式碼中,展示了幾個成功的SQL注入攻擊示例(包括基於聯合的和破壞性的),並通過您可以在C#中應用的實用SQL注入防止技術進行講解。 這篇文章遵循Tim的操作步驟,以便您可以看到他展示的確切問題和修復。

演示應用及其重要性

Tim從一個小型WPF演示應用開始,該應用連接一個本地InjectableDB(人物和秘密表)。 應用的類似Web表單的搜尋框接受使用者輸入(姓氏),並構建一個SQL查詢以返回ID、名字和姓氏。 它"運作" —— 輸入Corey即可得到Tim Corey —— 但Tim強調核心要點:"僅僅因為應用運作並不意味著它是安全的。"一個運作中的Web應用仍可能在將使用者提供的輸入直接插入到SQL語句中時,通過字串連接或動態SQL,引發SQL注入漏洞。

不安全的程式碼——字串連接和動態SQL

Tim展示了許多開發人員使用的確切不安全模式:

var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);
var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);

這個原始查詢使用字串連接來創建SQL語句。 Tim警告:如果您看到程式碼將使用者輸入直接注入SQL查詢,那麼停止 — 這是一個SQL注入漏洞。 攻擊者可以創建惡意輸入,改變您的SQL命令的結構,甚至運行附加的惡意SQL語句。

攻擊者如何利用它——UNION和DROP

為展示SQL注入攻擊的工作原理,Tim在SQL Server中再現查詢,然後使用UNION ALL和SQL註釋(--)來隱藏尾部字符進行注入。 Tim演示的惡意載荷示例:

  • 基於聯合的SQL注入以讀取其他表:

    UNION ALL SELECT ID, Username AS FirstName, Password AS LastName FROM Secrets;

    這將Secrets中的結果混合到原始SELECT結果集中,暴露諸如使用者名稱和密碼等敏感數據。

  • 破壞性注入以刪除表:

    DROP TABLE DemoTable;

    這通過用分號終止第一個語句,然後添加破壞性命令來運行第二個SQL語句(DROP TABLE)。 Tim展示表消失——資料庫已被惡意SQL修改。

Tim的觀點:攻擊者不需要提前知道表或列名 — 他們可以從資料庫伺服器枚舉表或列名,或只是嘗試盲目或基於時間的技術來發現行為。

修復1——參數化查詢

Tim的第一個也是主要的防禦措施是停止用使用者數據構建SQL字串。 用參數化查詢替代動態SQL:

string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });
string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });

Tim解釋參數化(預備語句樣式的使用)意味著資料庫將使用者提供的輸入嚴格作為數據處理——惡意的SQL僅成為字串值,無法改變SQL結構。 這可以防止許多常見的SQL注入攻擊,包括基於聯合的載荷和附加的; DROP TABLE命令。

他還建議將參數化與最小輸入驗證配對:對姓氏中不太可能出現的字符(例如分號或--註釋標記)進行清理或阻止,但允許有效字符如撇號(O'Reilly)。 參數化查詢 + 輸入清理可提供對SQL注入攻擊的重大保護。

修復2——儲存過程

Tim接下來展示兩個儲存過程:一個不安全的儲存過程在proc內連接SQL然後執行它,和一個直接使用參數的安全儲存過程。

  • 不安全的儲存過程從參數構建@sql字串並執行它——仍易受注入攻擊。

  • 安全儲存過程執行SELECT ... WHERE LastName = @LastName並使用參數執行——安全。

Tim澄清:如果您仍在儲存過程內構建動態SQL,它們不是自動治療的良藥。 但是當正確使用時(無動態SQL),儲存過程有助於集中化SQL語句,使其更容易參數化和審核查詢。 儲存過程也可以幫助簡化應用中的SQL注入防止。

不要信任任何數據——即使是資料庫數據

Tim提出的很重要且經常被忽視的一點:您不能盲目地信任從自己的SQL資料庫中檢索的數據。 攻擊者有時會在欄位中埋下惡意載荷(一顆"定時炸彈"),稍後將被另一過程連接到動態SQL中。 Tim堅持:始終在每一步使用參數並清理數據——無論是來自Web表單、文件上傳,還是您自己的資料庫——以便惡意輸入不能之後成為注入的途徑。

附加提示——最小特權和限制資料庫特權

除了程式碼修復外,Tim建議進行防禦性配置:限制應用帳戶的資料庫特權。 在他的演示中,連接使用透過整合安全的管理員帳戶——危險。 相反,使用最小特權原則:

  • 為應用創建一個只擁有所需權利的資料庫帳戶。

  • 如果您使用儲存過程,僅授予該帳戶對特定儲存過程的執行權限而無其他權限。

  • 不要給應用帳戶廣泛的管理員權限來允許DROP TABLE、列出所有表或讀取其他資料庫。

這減少了成功的SQL注入攻擊的影響——即使注入是可能的,攻擊者也不能超過帳戶被允許的權限。

Tim還指出Entity Framework會使這變得更複雜:EF經常需要提升的權限(遷移,結構更改)。 如果您在生產環境中使用EF,請仔細計劃其權限和部署。

總結——停止,參數化,清理,限制

Tim在他的影片最後以防止SQL注入在C#應用中的清單結尾:

  1. 停止使用字串連接或包含使用者輸入的動態SQL來建立SQL語句。

  2. 使用參數化查詢/預備語句範式,這樣使用者數據始終作為數據處理。

  3. 在適當的地方清理輸入(阻止分號,SQL註釋,意外字符)。

  4. 偏好使用安全的儲存過程(其中沒有動態SQL)來集中查詢邏輯。

  5. 對資料庫帳戶應用最小權限限制——限制應用的資料庫用戶的操作範圍。

  6. 審查程式碼(尤其是動態構建SQL的地方)並測試是否存在SQL注入漏洞。

Tim的最後警告:對使用者輸入的不當處理、動態SQL和過多的資料庫特權可能導致嚴重的漏洞——洩露敏感數據,破壞性地刪除表或長期未被發現的滲透。 將SQL注入防止視為核心安全要求,而不是可選的完善。

Hero Worlddot related to 什麼是SQL注入,如何在C#中預防?
Hero Affiliate related to 什麼是SQL注入,如何在C#中預防?

通過分享您所愛的東西賺得更多

您是否在為使用.NET、C#、Java、Python或Node.js的開發者創建內容?將您的專業知識轉化為額外收入!

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我