SQL Injection 是什麼?
SQL Injection(SQL 隱碼注入,亦稱 SQL 注入攻擊)是一種常見的網路安全漏洞,攻擊者透過在應用程式的輸入欄位中插入惡意的 SQL 資料查詢語句,誘使後端資料庫執行未經授權的指令。簡而言之,原本應該當作純文字輸入的內容被當成了資料庫指令來執行,導致攻擊者可以繞過應用程式的正常邏輯,對資料庫進行未預期的操作,例如竊取、竄改甚至刪除資料。這種攻擊手法最早在 1990 年代末期就已被提出並討論:據報導,關於 SQL Injection 的首次公開討論可追溯至 1998 年 Phrack 駭客雜誌上的一篇文章。由於 SQL Injection 攻擊的威力巨大且防範不當仍然常見,它長期以來反覆出現在 OWASP 前十大 Web 安全風險列表中 —— 在 2013 年時甚至被列為排名第一的嚴重漏洞,儘管近年來被歸類為更廣義的「注入」類風險,但依然位居前列。對網站開發者與資訊安全人員而言,理解 SQL Injection 是什麼 以及如何預防,至關重要。
現實中,成功的 SQL 資料隱碼注入攻擊可能對系統造成災難性影響。攻擊者可能藉此未經授權地取得資料庫中機敏的使用者個人資料、用戶帳號密碼,甚至偽造具有較高權限的管理者身分來控制資料庫。嚴重時,還可能執行系統層級的指令取得伺服器控制權。所幸,SQL Injection 本質上 並非難以防範的漏洞,只要遵循安全的開發實踐便可大幅降低風險。接下來,我們將介紹常見的 SQL Injection 攻擊手法、實際範例分析,以及 SQL Injection 防範 方法和安全測試重點。
常見的 SQL Injection 攻擊手法
SQL Injection 的攻擊手法多種多樣,攻擊者可因應目標應用程式回應的特性,採取不同策略。以下介紹幾種常見的 SQL 注入攻擊類型:
基於恆真條件的注入(Tautology-based Injection)
所謂「恆真條件」注入,是指攻擊者在輸入中構造永遠為真的布林表達式,典型例子如 OR 1=1
。這種攻擊常用於繞過登入驗證或資料庫查詢的限制。例如,正常情況下查詢可能期待一個使用者 ID,而攻擊者在該輸入位置加入 OR 1=1
後,整條查詢的 WHERE 條件將永遠為真,導致資料庫返回不該給予的所有資料。具體例子如下:
假設原始查詢為:
-- sql --
SELECT * FROM students WHERE studentId = 117;
如果攻擊者將輸入的學生ID改為 117 OR 1=1
,則查詢會變成:
-- sql --
SELECT * FROM students WHERE studentId = 117 OR 1=1;
因為 1=1
永遠為真,資料庫將忽略原本的限制條件,回傳整張 Students 資料表的所有內容。同樣道理,在網站的登入欄位中使用此類恆真語句也能繞過帳號密碼驗證,直接登入(下文將提供更詳細的例子)。此類攻擊手法利用了應用程式對輸入缺乏嚴格檢查的弱點,非常簡單卻危害嚴重。
基於 UNION 的注入(Union-based Injection)
Union 型 SQL 注入是利用 SQL 的 UNION
關鍵字,將惡意查詢結果與原查詢的結果合併,從而取得更多資料。攻擊者在可控制的輸入中插入 UNION SELECT ...
等片段,必須精心構造使其與原始查詢的欄位數和型別匹配。一旦成功,攻擊者便可透過 UNION
從其他資料表提取機密資訊。例如,如果原查詢為選取產品列表,攻擊者可能透過 UNION SELECT username, password FROM users
將使用者帳密資料附加在查詢結果後面回傳。這類攻擊要求資料庫允許多重查詢合併,但許多SQL資料庫(如 MySQL、SQL Server 等)都支援 UNION
,因此只要應用程式沒有防範,此手法威力同樣不可小覷。
基於錯誤訊息的注入(Error-based Injection)
錯誤訊息型 SQL 注入是利用資料庫回傳的錯誤資訊來進行攻擊的手法。攻擊者嘗試輸入惡意的SQL片段,使資料庫產生錯誤,從錯誤回報中套取有用的資訊。例如,攻擊者可能輸入引號等不完整的指令,迫使資料庫拋出包含 SQL 查詢或資料庫結構的錯誤訊息。透過分析這些錯誤訊息,攻擊者可以推斷資料庫的架構(如表格、欄位名稱)以及應用程式查詢語法,進一步完善攻擊策略。有經驗的攻擊者甚至會故意構造數學運算錯誤或字串轉型錯誤,以在錯誤訊息中直接獲取資料庫中的敏感資料。例如在某些資料庫,輸入 1/0
會拋出錯誤,錯誤內容可能包含攻擊者想取得的資料。由於現代許多應用為了安全,已不直接回傳詳細錯誤給用戶,此攻擊手法主要見於開發或除錯模式未關閉、錯誤處理不當的系統。
盲目型 SQL 注入(Blind SQL Injection)
所謂「盲注」(Blind SQL Injection),是指當應用程式並不直接回傳資料庫查詢結果或錯誤訊息時,攻擊者透過間接手段推測資料庫資訊的技巧。在盲注情況下,攻擊者無法從介面直接看到SQL執行結果,因此採用布林盲注或時間盲注等方法:
- 布林盲注(Boolean-based):攻擊者輸入的惡意語句包含條件判斷,根據條件真或假的情況,使應用程式的回應產生可察覺的不同。例如在一個需要登入的頁面,攻擊者輸入
admin' AND 1=1--
與admin' AND 1=2--
兩種payload,觀察應用程式回應的差別。如果前者回應正常而後者回應錯誤或行為不同,即可推斷出應用程式將1=1
評估為真,據此一點一滴推測資料庫內容(例如逐位元猜解密碼散列值,每次根據條件判斷一位元元是否正確)。 - 時間盲注(Time-based):有些情況下應用不會返回任何可見差異,攻擊者則利用資料庫的延遲函式進行判斷。例如在輸入中構造
IF(condition, sleep(5), 0)
之類的語句,若條件為真使資料庫延遲5秒回應,攻擊者觀察到回應延遲即可推知條件為真。藉由多次更改條件,透過回應時間的差異逐步推測資料庫中的資訊。
盲目式攻擊通常比前述類型耗時,但在目標應用沒有直接回顯時,是唯一可行的 SQL Injection 攻擊手段。攻擊者往往會編寫自動化腳本反覆送出試探性查詢,以在盲區中抽絲剝繭地獲取敏感資料。
實例分析:簡單漏洞程式碼與注入過程
下面透過一個簡化的例子,說明 SQL Injection 攻擊的實際運作方式。假設我們有一段網站登入驗證的程式碼,其功能是根據使用者輸入的帳號與密碼,查詢資料庫中是否存在對應的帳戶記錄:
// 以 PHP 為例的易受攻擊程式碼片段
$username = $_POST['user'];
$password = $_POST['pass'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password';";
上述程式直接將使用者輸入拼接進 SQL 查詢字串,沒有做任何檢查或參數化,因而存在 SQL Injection 漏洞。正常情況下,如果使用者輸入 user=admin
、pass=1234
,查詢字串會變成:
-- sql --
SELECT * FROM users WHERE username = 'admin' AND password = '1234';
若資料庫中存在 username 为 admin 且 password 为 1234 的記錄,網站就會讓該使用者登入。現在,攻擊者利用這段程式的漏洞,在「帳號」欄位中輸入特殊字串,而「密碼」欄位輸入任意值(或留空)。例如:
- 帳號輸入:
' OR '1'='1' --
- 密碼輸入:
(隨意)
此時,程式組合出的 SQL 查詢變為:
-- sql --
SELECT * FROM users WHERE username = '' OR '1'='1' -- ' AND password = '';
請注意,在上述查詢中:
username = '' OR '1'='1'
部分永遠為真(因為'1'='1'
為恆真條件);--
是 SQL 中的注解符號,將其後整行內容視為註解,使得原本的密碼條件AND password = ''
被當作註解忽略掉。
結果,整個 WHERE 條件等價於 TRUE
,資料庫將忽略帳號密碼匹配的限制,直接回傳 Users 資料表中的所有記錄。這意味著攻擊者不需要知道正確密碼,就成功繞過了驗證機制。如果 Users 資料表包含使用者名稱與密碼欄位,攻擊者此時即可獲取所有使用者的帳號密碼等機密資訊。

上述流程圖形象地展示了攻擊者透過惡意輸入繞過網站登入驗證的過程:攻擊者在前端提交特殊字串作為帳號,後端組合查詢時語法被竄改,資料庫因此查詢出第一筆使用者(通常為管理員帳戶)的資料並返回,應用程式錯誤地允許登入。整個過程中,攻擊者未提供正確密碼卻獲得了授權(如圖中所示,攻擊者成功以 admin 身份登入系統)。透過類似的技巧,攻擊者還可以進一步竊取更多資料甚至進行資料庫管理操作。
從上述範例可以看到,輸入驗證缺陷是 SQL Injection 發生的根本原因之一——應用程式沒有正確區分「資料」與「指令」的邊界。了解攻擊方式後,我們更需要關注的是如何預防此類漏洞。
SQL Injection 防範措施
預防 SQL Injection 攻擊需要開發人員和資料庫管理員在各方面採取嚴格的防護策略。以下介紹數項主流且有效的 SQL Injection 防範 方法:
使用參數化查詢(Prepared Statements)
參數化查詢是防止 SQL 注入的最有效手段之一。開發人員在撰寫 SQL 查詢時,不直接將使用者輸入的值拼接進字串,而是使用預先編譯好的查詢語句,將使用者輸入當作參數綁定。這種 預備語句(Prepared Statement)機制會強制資料庫將指令與資料分開處理,即使輸入中含有像單引號、SQL關鍵字等特殊符號,也只會被視為普通資料而不會被解讀為指令。例如,在 Java 中使用 JDBC 時,可以這樣寫查詢:
// java
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, userInput);
stmt.setString(2, pwdInput);
ResultSet rs = stmt.executeQuery();
如上,?
佔位符代替了直接拼接字串,setString
方法將輸入安全地綁定。這樣資料庫收到查詢時,會將整條查詢語句預先編譯,然後再把參數值代入執行。無論使用者輸入什麼,都無法改變查詢語句的結構。主流資料庫及開發框架幾乎都支援參數化查詢,如 PHP 的 PDO、Java 的 JDBC PreparedStatement
、.NET 的 SqlCommand
(使用參數)等。在使用高階 ORM(物件關聯對映)工具時,大多數情況下也會自動使用參數化查詢處理輸入。總之,永遠優先使用參數化查詢取代字串拼接,是防範 SQL Injection 的基石。
驗證與過濾使用者輸入
對使用者提供的輸入進行嚴格的驗證與過濾,同樣是防禦 SQL 注入的必要步驟。開發人員應該對每一個來自用戶的資料進行格式與型別上的檢查:
- 長度與格式校驗:限制字串的最大長度,並使用正則表達式等機制確保輸入內容符合預期格式。例如,使用者名稱僅允許字母和數字,電話號碼只能是數字等。這可避免攻擊者輸入超長或特殊格式字串企圖打亂查詢語法。
- 型別檢查:對於預期為數字的輸入,應驗證其確實為數字型別,或嘗試轉換型別後再使用。類似地,日期、電子郵件等也應檢查格式合法性。型別檢查可以在程式語言層面或使用資料庫本身的約束(constraint)來實現。
- 特殊字元過濾或轉義:根據應用情境,過濾掉或轉義一些在 SQL 中具有特殊意義的字元,例如單引號(
'
)、雙引號("
)、分號(;
)、連接符號(--
)等。所謂轉義(Escape)是指在特殊字元前加上反斜線等標記,使其失去作為指令的功能而僅被視為普通符號。大多數程式語言的資料庫函式庫都提供了自動轉義方法(如 PHP 的mysqli_real_escape_string
等),可在將輸入放入查詢前進行處理。但需注意,手動轉義容易遺漏且不同資料庫字元轉義規則不一,不應將轉義作為主要防線,而應輔助其他措施。
透過以上多層次的驗證與過濾,能夠在一定程度上降低惡意輸入導致注入攻擊的可能性。不過,輸入驗證只能減少明顯非法的輸入,仍不足以對抗技巧高明的攻擊;因此務必要配合參數化等其他防禦手段。
善用 ORM 與高階框架
使用成熟的資料庫訪問框架或 ORM(Object-Relational Mapper,物件關聯對映)也是防範 SQL Injection 的有效途徑之一。ORM 能讓開發人員以物件操作方式與資料庫交互,避免直接撰寫生 SQL 語句。一些知名的 ORM 工具(例如 Hibernate、Entity Framework、ActiveRecord 等)在底層實現中預設就會對輸入參數做參數化處理或轉義,從而降低發生注入的風險。不過,使用 ORM 並不代表萬無一失:開發人員仍需謹慎對待任何可以拼接 SQL 的介面。例如某些 ORM 允許直接執行原生 SQL 查詢(native query)或動態組裝查詢條件,如果在這些地方疏忽,依然可能引入 SQL Injection 漏洞。因此,我們建議在可能的情況下盡量使用框架提供的安全查詢接口,並遵守其安全使用規範。如果必須寫原生 SQL,請務必確保採用了參數化查詢或安全的轉義函式處理輸入。
其他防禦措施
除了上述主要措施外,還有一些輔助的防禦策略可以提高整體安全性:
- 最小權限原則:為資料庫使用者帳號設定最小必要的操作權限。也就是說,應用程式連接資料庫所使用的帳號只賦予其工作所需的讀寫權限,而沒有過多的管理權限。如此即便發生 SQL Injection,攻擊指令能造成的影響也被限制在最小範圍。例如,一個僅需查詢資料的網站帳號不應具有 DROP TABLE 或 ALTER 権限。切勿使用資料庫的 root 或 DBA 等高權限帳戶來連接應用。最小權限配置不能阻止注入發生,但能減輕其後果。
- 使用儲存程序(Stored Procedures):將固定的查詢邏輯寫成資料庫端的儲存程序,讓應用只透過呼叫儲存程序並傳入參數來進行操作。這樣可避免應用直接拼接 SQL,某些程度上降低注入風險。但需注意,儲存程序本身若動態拼接 SQL 字串,仍有注入風險,因此必須在儲存程序內部也使用參數化查詢。儲存程序的主要價值在於統一起來賦權與參數檢查。
- 隱藏錯誤詳情:確保應用在生產環境中不直接對用戶顯示詳細的資料庫錯誤訊息。攻擊者利用錯誤回傳來推斷資料庫結構的可能性應當被減到最低。可以將錯誤記錄在伺服器日誌中,呈現給用戶的則是一般性錯誤頁面。這對防範錯誤型注入攻擊特別重要。
- 部署 Web 應用防火牆(WAF):WAF 能夠過濾常見的惡意請求,例如檢測到請求 URL 或參數中含有 SQL 關鍵字(如 SELECT、UNION 等)或可疑模式時阻擋請求。雖然高明的攻擊可以繞過單純的關鍵字檢測,但現代的 AI 或行為式 WAF 在識別異常請求方面愈發智能,作為最後一道防線仍然相當有用。
綜合運用以上防禦措施,並在開發全程養成安全編碼習慣,才能有效杜絕 SQL Injection 等注入攻擊帶來的威脅。
弱點掃描與安全測試
即使開發過程中已採取各種防範措施,上線前仍應對網站進行弱點掃描與滲透測試,以確保沒有遺漏的 SQL Injection 漏洞。業界有許多工具和框架可協助自動化地檢測 SQL 注入風險:
- OWASP 安全檢測:OWASP(Open Web Application Security Project,開放式 Web 應用安全計畫)提供了豐富的資源來協助發現和防禦 Web 漏洞。開發團隊可以參考 OWASP Top Ten 的指引來了解常見漏洞(其中「Injection」類風險長期名列其中)以及測試要點。具體工具方面,OWASP 提供了知名的 ZAP (Zed Attack Proxy) 安全掃描器,可模擬各種惡意輸入對網站進行自動化掃描。OWASP ZAP 對 SQL Injection 有內建的檢測規則,能嘗試在表單欄位、URL 參數中注入特殊字串,觀察應用回應,以發現可能的漏洞。由於它開源且功能強大,非常適合開發者在開發或佈署前自行掃描網站的安全性。
- Burp Suite 滲透測試:Burp Suite 是另一款廣泛使用的 Web 安全測試工具組,尤其受專業滲透測試人員青睞。Burp Suite 提供了攔截代理、掃描器、模糊測試(Fuzzing)等模組,可以半自動地發現 SQL Injection 等漏洞。使用者可透過 Burp 的自動掃描功能快速檢查常見注入點,同時也能利用其 Intruder 模組手動設定更精細的惡意字串列表進行測試。例如,在上一節的登入例子中,測試人員可以使用 Burp 拋送一系列像
' OR '1'='1
、admin'--
、' OR ASCII(SUBSTR(password,1,1))=65 --
等payload觀察伺服器回應,從中確定應用是否存在盲注或其他注入弱點。Burp Suite 提供的回應差異高亮和自動化payload生成,能大幅提高人工測試 SQL Injection 的效率與準確度。 - 專業弱點掃描工具:除了上述兩款開源或社群版工具,還有許多專門針對 SQL 注入的掃描或利用工具。例如 sqlmap 是一個開源的自動化 SQL Injection 測試工具,能對目標URL進行深入測試並在發現漏洞時自動嘗試提取資料庫資料。SQLNinja 則專注於幫助測試者在 Microsoft SQL Server 環境下利用注入漏洞取得系統權限。這些工具往往帶有資料庫指紋識別、資料提取、甚至進階的OS指令執行等功能,可用於模擬最糟糕的攻擊情境。但需要注意,在未經授權的情況下使用此類工具掃描他人系統可能觸法,應只在合法授權的測試範圍內使用。
在實務上,建議將安全測試融入開發流程中,對新的程式碼變更定期進行檢查。例如,在持續整合/部署(CI/CD)流程中加入自動化安全掃描,或在產品上線前由專業的資訊安全團隊進行滲透測試。藉由這些 弱點掃描與安全測試 手段,可以及早發現並修補 SQL Injection 漏洞,將風險阻絕在攻擊者利用之前。一旦發現漏洞,應立即依照前述防範措施加以修正,例如採用參數化查詢、加強輸入驗證或調整資料庫權限,確保同類型問題不再發生。
結語
SQL Injection(SQL 資料隱碼注入)是一個歷史悠久但仍具高度危險性的漏洞類型。它利用應用程式對輸入處理的疏漏,讓攻擊者有機可乘地對資料庫下達惡意指令。我們回顧了 SQL Injection 是什麼 以及幾種常見攻擊手法,包括恆真條件注入、Union 注入、錯誤訊息注入和盲目注入等,並透過實例展示了攻擊如何發生及其嚴重後果。所幸,針對 SQL Injection 防範 已有成熟的對策,例如使用參數化查詢、防範未經過濾的輸入、善用 ORM 框架等。安全是一個全方位的課題,除了在開發階段編寫安全的程式碼,也需要透過 OWASP、Burp Suite 等工具進行充分的弱點掃描與測試。唯有將預防措施和安全測試相結合,才能有效杜絕 SQL 注入攻擊,保障網站和資料庫的安全。正如資安領域的箴言:「永遠不要信任使用者的輸入」,只要我們秉持這一原則並採取適當的防護措施,便能讓 SQL Injection 無計可施。
參考資料:
OWASP Top 10 (2023) 中的 Injection 風險說明 shehome.website
維基百科:SQL 注入的定義與原理 zh.wikipedia.org zh.wikipedia.org
Cloudflare 資安知識庫:SQL 資料隱碼攻擊介紹 cloudflare.com cloudflare.com
PHP 官方手冊:SQL Injection 攻擊範例與說明 php.net
ManageEngine 資安部落格:SQL Injection 攻擊流程解析 manageengine.com manageengine.com
《零基礎資安系列:認識注入攻擊》:SQL 注入防禦建議 shehome.website shehome.website