產業資訊

資安知識18 分鐘閱讀

SQL Injection 是什麼?原理、類型、檢測與修復完整指南

SQL Injection 的根因不是輸入中出現特殊字元,而是應用程式讓外部資料改變 SQL 指令結構。完整解析常見類型、檢測證據、參數化查詢、ORM 與 Stored Procedure 誤區,以及修復後複驗。

SQL Injection(SQL 注入)發生在應用程式把不受信任的輸入當成 SQL 指令的一部分,讓攻擊者有機會改變原本只想查詢一筆資料的語意。真正有效的防護不是持續擴充黑名單,而是讓 SQL 結構固定、外部輸入只能以資料參數傳入,再以最小資料庫權限限制失守時的影響。

網站表單輸入被錯誤拼入 SQL 查詢結構後,資料庫輸出超出原本範圍的多筆紀錄並顯示風險警示
01

先講結論:SQL Injection 是資料改變了查詢指令

正常情況下,網站應先定義固定的 SQL 指令結構,再把使用者提供的帳號、搜尋詞、篩選值或識別碼放進資料參數。SQL Injection 出現時,應用程式沒有守住這條邊界,使外部資料被資料庫解讀成運算子、條件、子查詢或其他 SQL 結構,原本的查詢意圖因此被改寫。

MITRE 將這類問題歸為 CWE-89:對 SQL 指令中的特殊元素處理不當。OWASP Top 10:2025 則把 Injection 列為 A05,並把『讓資料與指令保持分離』列為首要防護原則。這也是為什麼只過濾引號、SQL 關鍵字或特定字串無法根治:不同資料庫、編碼與查詢上下文仍可能有其他語法路徑。

安全設計的核心可以濃縮成一句話:應用程式決定查詢結構,使用者只能提供資料值。只要把這個不變條件落實在所有資料存取層,SQL Injection 的主要攻擊路徑就會被切斷。

  • 固定 SQL 結構:查詢語意由程式碼或可信資料存取層定義
  • 參數綁定:外部輸入以具型別的值傳入,不參與 SQL 語法解析
  • 伺服器端允許清單:欄位、排序方向等無法參數化的結構由固定對照表選取
  • 最小權限:應用程式資料庫帳號只擁有完成業務所需的最低權限
  • 可驗證複驗:修復後不只確認畫面正常,還要證明所有同根因查詢都已改正
02

從 HTTP 請求到資料庫:風險在哪一段產生?

SQL Injection 並不是資料庫單方面的問題。典型資料流會經過瀏覽器或 API Client、路由與 Controller、商業邏輯、資料存取層、資料庫驅動程式,最後才到資料庫。風險通常產生在某一層把外部輸入與 SQL 字串直接串接,或把原本應為資料的值交給可以執行動態 SQL 的介面。

輸入來源也不只網址列和表單。JSON Body、GraphQL 變數、Cookie、HTTP Header、排序欄位、匯入檔案、Webhook、訊息佇列,以及先被儲存、之後再組成查詢的資料,都可能穿越信任邊界。只檢查公開搜尋框,無法代表整個網站沒有 SQL Injection。

下圖左側呈現錯誤資料流:紅色輸入直接成為查詢結構的一塊,使資料庫回傳超過預期的紀錄。檢測與修復都應沿著同一條資料流定位:輸入在哪裡進入、經過哪些轉換、由哪個 API 組成查詢、使用哪個資料庫帳號執行,以及結果如何回到使用者。

SQL Injection 常見輸入來源與容易忽略的檢查點
輸入來源常見位置容易漏掉的情境
URL 與表單Query String、Path、登入、搜尋與篩選數字 ID、分頁、排序與隱藏欄位也屬外部輸入
API 資料JSON、XML、GraphQL、REST Path/Body巢狀欄位、批次參數與未在前端顯示的 API
HTTP 狀態Cookie、User-Agent、Referer、自訂 Header日誌、分析或風控流程可能把 Header 再寫入資料庫
儲存資料個人資料、內容、檔案 Metadata、Webhook寫入時安全,但在後續報表或後台查詢被動態串接
後台與整合管理介面、排程、匯入、訊息佇列被視為可信的內部來源仍可能攜帶外部資料
03

SQL Injection 有哪些類型?差異在取得回饋的方式

SQL Injection 的分類常依攻擊者如何觀察結果,而不是依根因區分。無論是錯誤訊息、同一頁面的內容差異、真假條件造成的行為差異,或資料庫回應時間,根因仍是外部資料改變了查詢結構。分類的價值在於協助測試人員選擇證據與修復人員理解暴露面,而不是提供未授權攻擊操作。

有些弱點能直接在 HTTP 回應看到資料,稱為 in-band;有些只能從真假條件或時間推論,稱為 inferential/blind;少數情境會讓資料庫透過另一個通道產生互動,稱為 out-of-band。Second-order SQL Injection 則強調惡意資料先被正常儲存,直到另一個功能讀取並拼接時才觸發。

檢測時不應只追求畫面出現資料庫錯誤。正式環境可能隱藏錯誤,CDN 或 WAF 也可能改寫回應;反過來,單次變慢或錯誤頁也不等於 SQL Injection。可靠判定要有可控制的基線、重複結果、伺服器端日誌或程式碼資料流等交叉證據。

SQL Injection 類型、觀察訊號與主要風險
類型測試時可能觀察到的訊號判讀重點
Error-based特定輸入造成穩定且與資料庫相關的錯誤差異避免把一般驗證錯誤或代理錯誤誤判為資料庫錯誤
UNION/In-band查詢結果結構被改變,回應出現超出原意的資料確認資料確由相同查詢路徑產生,並立即停止敏感資料擷取
Boolean-based Blind控制真假條件時,狀態、內容長度或業務結果呈一致差異需排除快取、個人化、負載平衡與隨機內容
Time-based Blind控制條件與回應延遲呈可重複的因果關係需建立多次基線並設定負載與停止條件,避免影響服務
Out-of-band資料庫或後端服務嘗試透過另一通道互動僅在明確授權與隔離環境驗證,檢查資料庫網路權限
Second-order資料寫入時無異常,之後在報表、後台或批次查詢中觸發追蹤資料生命週期,不能因輸入已存入資料庫就視為可信
04

影響不只資料外洩,也可能破壞完整性與可用性

SQL Injection 最常被聯想到資料讀取,但實際影響取決於查詢功能、資料庫帳號權限、驅動程式設定、資料庫產品與部署架構。弱點可能造成未授權查詢、登入或篩選條件繞過、資料竄改或刪除,也可能讓攻擊者取得更多資料庫權限。若資料庫帳號過度授權,風險會被顯著放大。

並非每個 SQL Injection 都能直接取得整個資料庫或作業系統權限。報告應區分已證實的行為、合理可達的影響與尚未驗證的最壞情境。過度誇大會讓開發團隊失去信任;只因沒有展示敏感資料就低估風險,也會錯失真正的修復時機。

評估業務影響時,要把受影響資料表、資料分類、租戶隔離、交易完整性、稽核紀錄與服務可用性納入。對會員、醫療、金融或企業管理系統而言,即使只影響一個查詢,也可能跨越重要的授權與資料邊界。

  • 機密性:讀取非本人、其他租戶、個資、憑證或商業機密
  • 完整性:變更帳號、訂單、權限、內容、交易或稽核資料
  • 可用性:高成本查詢、鎖定、資料破壞或資源耗盡造成服務異常
  • 權限邊界:繞過原有篩選或存取控制,擴大到資料庫帳號可及範圍
  • 法規與事件應變:若存在實際利用跡象,需評估保存證據、通報與受影響資料
05

怎麼安全檢測?先有授權、基線與停止條件

SQL Injection 測試必須在明確授權範圍內執行。測試計畫要列出網域、API、環境、帳號、允許方法、資料庫與業務限制,並事先定義可接受的驗證深度。對生產環境應優先使用無破壞性證據,限制併發、延遲與資料量,並設定錯誤率、延遲、交易異常或告警觸發時的停止條件。

有效驗證會先建立正常請求基線,再一次只改變一個輸入,觀察回應狀態、內容結構、時間與伺服器端紀錄是否呈現可重複差異。測試結果應能被另一位驗證者理解與重測,但不需要大量擷取資料、修改真實紀錄或執行破壞性操作來證明風險。

若能存取程式碼或 APM/資料庫追蹤,應同步確認輸入如何到達查詢,以及驅動程式收到的是預先編譯的查詢與參數,還是一段已拼接完成的 SQL 字串。動態測試證明實際行為,資料流與查詢追蹤則協助確認根因;兩者結合會比單一錯誤訊息可靠。

06

一筆可信的 SQL Injection 發現需要哪些證據?

報告至少要回答:哪個資產、哪條路徑、哪種方法、哪個參數、什麼角色與租戶、在什麼時間與版本下出現差異。若只寫『登入頁存在 SQL Injection』,開發人員通常無法定位查詢,也無法判斷是否只出現在測試環境或特定節點。

證據應呈現安全基線與測試條件的差異,並說明為什麼差異支持查詢結構被改變。可以保存遮罩後的請求/回應片段、回應雜湊、狀態與長度、重複時間統計、應用程式錯誤 ID、APM Trace、資料庫 Query Log 或程式碼路徑;不應把完整個資、Session、密碼或大量資料直接放入一般工單。

嚴重度則要分開評估。技術證據證明弱點存在,資產暴露、所需權限、可讀寫資料、資料庫帳號權限與補償性控制決定處置優先級。保留這兩層資訊,才能避免把『有弱點』與『風險多大』混為一談。

SQL Injection 最小可複驗證據包
證據應記錄內容保護要求
資產與條件Host、路徑、方法、參數、角色、租戶、環境與版本避免只記 IP 或模糊功能名稱
正常基線安全輸入下的狀態、內容特徵、時間與業務結果保存足以比較的特徵,不必保存完整敏感頁面
驗證差異一次一變因且可重複的回應、錯誤、時間或查詢差異不執行刪除、批次匯出或高負載驗證
根因線索資料流、Query Trace、日誌事件、程式碼位置或框架用法限制日誌權限並遮罩參數值
影響範圍查詢目的、資料表、資料分類、DB 帳號與可用操作區分已證實與推測的最壞情境
複驗資料修復版本、部署環境、原始測試條件與預期安全結果讓驗證者能重測而不暴露可濫用細節
07

核心修復:使用參數化查詢或 Prepared Statement

參數化查詢會先把 SQL 指令模板交給資料庫,再以獨立參數傳入資料值。資料庫知道哪些部分是指令、哪些部分是資料,因此即使參數包含具有 SQL 意義的字元,也只會被當成值處理。OWASP、CWE-89 與 ASVS 都把這種 code/data separation 視為主要防護。

修復不能只改報告中的單一路徑。團隊應搜尋相同 Repository、DAO、Query Builder、Raw SQL Helper、批次與報表程式,確認同一套字串串接模式沒有存在其他端點。若共用函式本身不安全,只改呼叫端容易留下變形路徑。

參數型別也應與資料模型一致。識別碼使用整數或 UUID,日期使用日期型別,布林值與列舉使用明確型別;這不取代參數化,但能縮小錯誤輸入與業務邏輯歧義。下圖右側呈現安全資料流:查詢結構保持完整,輸入進入獨立參數槽,資料庫只回傳預期紀錄。

修復前外部輸入插入 SQL 查詢結構並造成過量資料輸出,修復後固定查詢與獨立參數槽分離並只回傳預期紀錄
參數化查詢的重點不是清理每一個危險字元,而是從架構上禁止資料成為 SQL 指令。
08

無法參數化的欄位名稱、排序與表格怎麼處理?

參數通常只能代表資料值,不能直接代替資料表名稱、欄位名稱、排序方向或 SQL 關鍵字。如果產品允許使用者選擇排序欄位或報表維度,不能把前端傳來的名稱直接拼進查詢,也不能只靠移除特殊字元。

正確作法是由伺服器端建立固定對照表。例如外部值 newest 只能映射到程式碼內預先定義的建立時間降冪排序;未知值直接拒絕或使用安全預設。資料表切換、報表欄位與聚合方式也應由可信列舉選取,不接受任意 SQL 片段。

如果需求真的需要高度動態查詢,應使用能保留參數綁定的成熟 Query Builder,對每個可變結構建立明確語法模型與允許清單,並進行專門的程式碼審查與測試。『動態』不等於必須用自由格式字串。

  • 資料值:使用 Prepared Statement 或框架原生參數綁定
  • 排序欄位:外部選項映射到伺服器端固定欄位列舉
  • 升冪/降冪:使用布林或列舉決定預先定義的 ASC/DESC
  • 表格與報表維度:依業務場景選擇固定查詢模板
  • 複雜篩選:使用參數安全且經審查的 Query Builder,不接受 Raw SQL Fragment
09

ORM、Query Builder 與 Stored Procedure 不是自動安全

ORM 能降低手寫 SQL 的比例,但只要使用 Raw Query、字串插值、自由格式條件、動態排序或不安全的 Query Builder Escape Hatch,仍可能把外部輸入帶回 SQL 結構。OWASP Top 10:2025 也特別提醒,未經處理的 ORM 搜尋參數仍可能暴露未授權紀錄。

Stored Procedure 只有在內部使用固定 SQL 與安全參數時才有防護效果。如果 Procedure 仍把參數串接後交給動態執行功能,風險只是從應用程式搬到資料庫。更糟的是,組織可能為了執行 Procedure 給應用程式過高權限,使成功利用的影響更大。

審查時不要只問『有沒有 ORM』或『是不是 Stored Procedure』,而要追到最終資料庫呼叫:Query Template 是否固定?值是否透過驅動程式參數傳入?是否存在 Raw SQL 與動態執行?資料庫帳號實際擁有哪些權限?

常見防護方式的有效性與限制
方式能否作為主要防護必要條件與限制
參數化查詢/Prepared Statement可以所有資料值都以驅動程式參數傳入,沒有先自行拼接 SQL
安全 ORM API可以避開 Raw SQL、自由格式 Filter/Order,確認框架確實使用參數綁定
Stored Procedure有條件Procedure 內不得動態串接 SQL,執行帳號仍需最小權限
允許清單驗證輔助/結構必要適用無法參數化的欄位、排序與有限選項,不取代值的參數化
輸入跳脫不建議作主要防護依資料庫、編碼與上下文而異,容易遺漏或錯用
WAF/RASP只能補強可降低部分已知攻擊,但可能被繞過,也無法修正程式根因
10

輸入驗證很重要,但不能取代參數化

輸入驗證的任務是確保資料符合業務規則,例如 ID 必須是合法 UUID、數量在允許範圍、狀態值屬於固定集合。它能減少模糊輸入、改善錯誤處理並縮小攻擊面,但不能保證資料不會改變 SQL 結構,因為合法資料本身也可能包含引號、連字號、Unicode 或其他被錯誤處理的內容。

常見反模式包括封鎖 SQL 關鍵字、移除引號、用正規表示式猜測攻擊 Payload,或只做瀏覽器端驗證。黑名單無法涵蓋不同編碼、大小寫、註解與資料庫方言;前端檢查則能被直接呼叫 API 繞過。

正確順序是先以參數化確保資料不會成為指令,再以伺服器端允許清單與型別/範圍驗證確保資料符合業務需求。輸出編碼是 XSS 等輸出情境的重要控制,但也不是 SQL Injection 的替代修復。

11

用最小權限限制成功利用後的爆炸半徑

即使程式已有參數化,資料庫權限仍應遵循 least privilege。應用程式不該使用 DBA、Schema Owner 或可建立帳號與任意物件的帳號連線。不同服務、環境與讀寫用途應盡量分離帳號,讓一個查詢路徑失守時無法橫跨全部資料與管理功能。

OWASP 建議從需求出發授權,而不是先給完整權限再期待應用程式自行限制。只需要讀取特定資料的功能,可透過唯讀帳號、受限 View 或固定 Procedure 暴露必要欄位;寫入功能則限制到特定表格與操作。資料庫執行所使用的作業系統帳號也不應具管理權限。

權限調整前要盤點現有查詢與排程,避免直接收權造成營運中斷。完成後應用自動化測試確認正常流程,並由資料庫端實際檢查授權,而不是只相信文件。若懷疑 SQL Injection 已被利用,還要評估輪替資料庫憑證與其他可被讀取的祕密。

  • 生產、測試與開發使用不同帳號與憑證,不共用高權限連線
  • 依服務與讀寫用途分離帳號,限制可見 Schema、Table、View 與操作
  • 禁止應用程式帳號建立使用者、授權、載入外部檔案或執行非必要管理功能
  • 用 Vault/Secret Manager 管理短週期憑證,避免寫入程式碼與映像檔
  • 持續檢查實際 Grants、閒置帳號、權限漂移與異常大量查詢
12

錯誤處理、日誌與監控:外部少揭露,內部要可追查

對使用者的錯誤訊息不應包含 SQL 片段、資料表、欄位、資料庫產品、Stack Trace 或內部路徑;這些資訊會協助攻擊者理解查詢與架構。前端可以回傳一致的業務錯誤與關聯 ID,詳細原因則保存於受保護的伺服器端日誌。

內部日誌要能關聯請求、使用者、服務、查詢模板、資料庫錯誤與部署版本,但不要無限制記錄完整參數、密碼、Token 或敏感資料。較安全的方式是記錄查詢模板 ID、參數型別、遮罩值、資料列數、耗時與 Trace ID,並對異常錯誤、回傳量或查詢時間建立告警。

監控不是修復,但能縮短發現與應變時間。若同一來源在多個參數產生資料庫語法錯誤、真假條件型回應差異、異常延遲或大量資料列輸出,安全團隊應能追蹤到應用程式與資料庫事件。告警規則也要調整誤報,避免正常搜尋與報表被當成攻擊。

13

WAF 可以暫時降低暴露,但不能當作結案證據

WAF 能封鎖部分已知 Payload、爭取修復時間並提供攻擊觀測,在公開高風險端點或緊急事件中很有價值。但 WAF 只看到經過它的流量,可能漏掉其他 Host、API、內部路徑、編碼、非 HTTP 資料來源與 Second-order 路徑,也可能因規則放寬或架構變更失去覆蓋。

因此 WAF 應記錄為補償性控制:規則適用哪些資產與路徑、阻擋或監控模式、如何測試、何時到期、誰監看、控制失效如何告警。即使控制有效,程式中的字串串接根因仍存在,修復工單與複驗責任不能直接關閉。

若暫時只能部署 WAF,優先建立精準規則、限制受影響功能、降低資料庫權限、提高監控並安排永久修復。之後複驗應分別確認應用程式根因消失與 WAF 不是唯一防線。

14

把 SAST、DAST、IAST、程式碼審查與資料庫觀測放在一起

不同方法看到的是 SQL Injection 的不同切面。SAST 可沿著資料流尋找輸入到危險查詢 API 的路徑,但可能不了解執行時框架與設定;DAST 從執行中的網站觀察可利用行為,但未必能覆蓋所有登入角色與隱藏功能;IAST 在測試流量下追蹤應用程式內部資料流,能協助定位 Sink,但依賴完整測試覆蓋。

程式碼審查適合檢查共用 Query Helper、Raw SQL、Stored Procedure 與動態排序等高風險設計;資料庫 Query Log、APM 與 Runtime Telemetry 則能驗證實際查詢模板、參數使用與異常結果量。沒有任何單一工具能保證所有路徑都被測到。

成熟流程會在開發階段以安全 API、Lint/SAST 與 Review 防止新問題,在整合與測試環境用 IAST/DAST 驗證,在正式環境持續監控錯誤與異常查詢,最後把每次發現回饋到安全編碼規則與回歸測試。

15

修復後怎麼複驗?不能只確認錯誤訊息消失

SQL Injection 複驗應先用原始資產、角色、路徑、方法與參數重現基線,再確認造成差異的測試條件不再改變查詢結果、時間或錯誤。單純把錯誤頁改成通用訊息,或讓 WAF 回傳 403,並不證明底層查詢已安全。

驗證者應取得修復版本與部署範圍,必要時檢查 Query Trace 或程式碼,確認查詢模板固定且參數由驅動程式綁定。接著擴大到同根因端點、其他角色、API 版本、批次與報表功能,並測試正常輸入、合法特殊字元與邊界值,避免修復造成搜尋或國際化資料損壞。

最後檢查資料庫帳號權限、錯誤訊息、監控與回歸測試是否同步改善。若只修正一個 Controller,卻保留共用不安全 Helper 或 Stored Procedure,工單不應視為完整結案。

SQL Injection 修復後的複驗條件
複驗面向通過條件不充分的證據
原始發現相同條件不再改變查詢語意,且正常功能維持頁面不再顯示錯誤
根因Query Template 固定,資料值由驅動程式參數綁定程式碼增加字元過濾
同根因範圍相關端點、角色、API 版本、批次與報表均完成檢查只測報告中的單一路徑
動態結構欄位、排序與表格由伺服器端允許清單選取前端 Dropdown 限制選項
權限與曝露DB 帳號最小權限,錯誤不外洩,必要監控已啟用WAF 規則目前會阻擋
回歸正常資料、合法特殊字元、邊界值與多語系輸入可正確運作只測攻擊型輸入
16

如果懷疑已遭利用,從弱點修復切換到事件應變

若日誌出現可疑查詢、異常大量資料、權限變更、資料庫錯誤探測或不明外連,工作不再只是修一個 Bug。團隊應依事件應變程序保存應用程式、WAF、資料庫、身分、主機與網路證據,限制受影響功能或帳號,並確認攻擊時間、入口、資料存取與橫向移動範圍。

修復程式與封鎖來源不能取代影響評估。若資料庫憑證、API Key、Session Secret 或其他機密可能被讀取,應依風險輪替;若資料遭未授權存取或變更,還要評估備份、完整性驗證、法規、契約與通報義務。

調查期間要避免破壞證據,並保留明確時間線。完成根因修正後,仍需驗證入侵持久化、異常帳號、資料變更與其他同類端點,而不是只確認原始 URL 回應正常。

17

開發與維運團隊的 SQL Injection 防護清單

SQL Injection 防護不應等掃描報告才開始。把安全查詢 API、Raw SQL 審查、最小權限、錯誤處理與自動化測試變成 Definition of Done,能在問題進入正式環境前切斷大部分風險。以下清單可用於設計審查、Pull Request、發布與複驗。

  • 所有資料值使用參數化查詢;禁止以字串插值或串接建立 SQL
  • 動態欄位、排序與表格使用伺服器端固定映射,不接受任意 SQL Fragment
  • 盤點 ORM Raw Query、Stored Procedure、Query Builder Escape Hatch 與共用 Helper
  • 伺服器端執行型別、範圍與允許清單驗證,但不把過濾當成主要防護
  • 應用程式資料庫帳號依服務與讀寫需求最小化,定期檢查 Grants 與權限漂移
  • 對外錯誤不洩漏 SQL/Schema,內部日誌可關聯且遮罩敏感參數
  • 在 CI 執行 SAST/測試,在授權環境執行 DAST/IAST,為已修復根因建立回歸案例
  • 修復後由獨立驗證者重測原始條件、同根因範圍、正常功能與資料庫權限
18

真正的修復,是讓資料永遠只能是資料

SQL Injection 看似有許多類型與測試技巧,但防護原則非常穩定:查詢結構必須由可信程式碼決定,外部輸入只能透過參數綁定成為資料。對無法參數化的結構使用伺服器端允許清單,再用最小權限、錯誤處理、監控與多種測試方法建立縱深防禦。

專業的弱點處理也不以『擋住一個 Payload』為終點。團隊要保存可複驗證據、定位共用根因、檢查 ORM 與 Stored Procedure 的真實用法、修正所有同類路徑,最後以查詢行為、正常回歸與資料庫權限共同證明風險已關閉。

REF

資料來源

Redmark Editorial
START WITH ONE WEBSITE

從第一個網站開始,建立持續弱掃流程

以更低的執行成本持續檢測網站弱點,更早發現問題,也讓每一次修復都有清楚的方向。

免費開始掃描