前言
不管是在網站或是應用程式開發等等,許多時候我們會用資料庫來儲存資料。而除非你用的是NoSQL資料庫,不然大多數都使用SQL作為查詢語言。
發生條件
- 有使用者輸入欄位
- 使用SQL查詢語言
- 沒有檢查或保護機制
- 使用者很壞
運作方式
欄位裡輸入一些SQL指令再搭配正確位置的單(雙)引號讓輸入的指令脫離字串使其可以執行。
範例:PHP搭配MySQL資料庫
情況:假設現在有一個表單為使用者輸入任何名稱,提交後透過SQL指令在資料庫查詢。
HTML Code:
<form method="POST">
<input type="text" name="userInput" placeholder="輸入查詢名稱">
<button type="submit">查詢</button>
</form>
PHP Code:
$userInput = $_POST['userInput'];
$conn = mysqli_connect('localhost', 'root', '', 'db');
$sql = "SELECT * FROM users WHERE username='$userInput'";
$result = mysqli_query($sql);
.
.
.
正常使用者:在欄位輸入一般名稱如,這時候SQL指令如下:
$sql = "SELECT * FROM users WHERE username='Grandpa'"; #在資料庫尋找Grandpa
不正常使用者:在欄位輸入如,這時候SQL指令如下:
$sql = "SELECT * FROM users WHERE username='' OR 1='1'"; #1='1'這個永遠都是True所以這個指令會從資料庫中選取所有資料
上面的SQL就已經很危險了,如果更可惡一點可以在欄位輸入如,這時候SQL指令如下:
$sql = "SELECT * FROM users WHERE username=''; DROP TABLE 'users'"; #直接把users表格刪除
如何防禦
- 最直接及有效的方法就是使用Prepared Statement
- 可以寫一個保護機制,例如:限制只能用英文及數字之類的
- PHP有內建
mysqli_real_escape_string();
如果用第三個的話我個人是建議改用第一個,畢竟它更有效而mysqli_real_escape_string();
在特殊的SQL Injection也沒有辦法完全的防禦。
第二個方法則是看你怎麼寫,寫的好可以完全防禦,反之,可能比沒有寫更爛。
NoSQL資料庫就沒有Injection攻擊嗎?
使用NoSQL資料庫(如:MongoDB…)代表不使用SQL為查詢語言當然就不會有SQL Injection的攻擊,但還是逃不過其他的Injection攻擊,所以並不是說用了NoSQL資料庫就不需要保護機制。
至於安全上,也是可以寫一個保護機制來限制使用者輸入的內容來達到有效的防禦。