名詞解釋
什麼是 SQL injection(SQLi)——能用輸入改寫資料庫命令的漏洞
SQL injection(SQLi)是一種讓使用者的輸入改寫資料庫命令(SQL)含義的漏洞。它會導致資料被讀取、被竄改、被全部刪除。本文用圖解講解原理,並以防禦視角(不公開攻擊手法)介紹真正有效的防禦:佔位符=prepared statement、ORM、最小權限資料庫。
「在搜尋框裡輸入的文字,竟成了資料庫『命令的一部分』」——這就是 SQL injection。本文講解它的原理與可靠的防禦方法(不公開攻擊手法)。
為什麼會發生(原理)
危險的根源在於用字串串接來組裝 SQL 語句。一旦「把輸入直接混進語句裡」,輸入就會越過「值」的邊界,作為「命令」生效。
✗ 字串串接(危險)
把輸入直接拼進語句 → 輸入可能被解釋為命令的一部分
✓ 佔位符(安全)
值作為「資料」傳入 ? / $1 等佔位框 → 始終只是值
受害範圍是「那個資料庫連線能做的一切」。一旦能觸及內部資料庫,它就和 RCE、SSRF 並列,成為大規模外洩的典型入口。
防禦
使用佔位符(prepared statement)(最重要)
組裝 SQL 時不使用字串串接。值透過 ? / 具名參數等作為「資料」傳入。僅此一項,就能讓這一類漏洞幾乎消失。
交給 ORM/查詢建構器處理
多數 ORM 預設使用佔位符。越少自己寫裸 SQL 就越安全。即便必須寫裸 SQL,也務必參數化。
把資料庫使用者設為最小權限
不要給應用用的資料庫使用者多餘的權限(DROP、其他資料表、管理操作)。即使萬一被攻破,也能縮小受害範圍。
輸入校驗作為「輔助」
對型別、長度、格式做校驗是有效的,但不要把它單獨當作防禦的主力。它只是佔位符之上的額外加強。
本站觀點:從根本上不再「手工拼裸 SQL」
SQLi 存在已久卻始終消除不掉——原因在於「圖方便,就把輸入混進語句裡」。本站的立場很明確:不製造把值用字串串接放進 SQL 的場景。只要把佔位符或 ORM 設為預設,這個漏洞就會在設計階段從結構上消失。請不要走「靠手動跳脫硬扛」的方向。
盲點:佔位符只能傳「值」
佔位符並非萬能。它能傳的只有 值,而對**資料表名、欄位名、ORDER BY 的方向(升冪/降冪)**這類「查詢的結構」無能為力。
當你想把這部分做成動態的(例如:讓使用者選擇「排序鍵」「篩選欄位」),不要把輸入直接放進 SQL,而應從事先確定的許可清單裡挑出對應的正規名稱。「排序欄位」「過濾欄位」正是那種容易因「以為佔位符已經守住了」而麻痺大意的典型盲點。
接下來閱讀
FAQ
QSQL injection 會造成什麼後果?
攻擊者可以改變資料庫查詢的含義,讀取本不該看到的資料、竄改資料,最糟時甚至能全部刪除或繞過身分驗證。它是個人資訊大規模外洩的典型原因之一。
Q最可靠的防禦是什麼?
就是「用佔位符(prepared statement)傳值」。組裝 SQL 語句時不使用字串串接,值始終作為「資料」透過另一條路徑傳入。這樣輸入就沒有被當作命令解釋的餘地了。多數 ORM 預設就這麼做。
Q對輸入做跳脫就夠了嗎?
手動跳脫容易遺漏,不推薦。真正有效的還是佔位符。此外要把資料庫使用者設為最小權限,以備萬一來縮小受害範圍。