0x00 背景
自己一個人學(xué)了這么久的web安全沫屡,感覺需要一些總結(jié),加上今天下午電話面試總被問到的問題俱饿,自己總結(jié)了一下寫出來和大家分享筑悴。(小白一個,也算自己記錄一下稍途,大佬勿噴)
0x01SQL注入實例
這里就以DVWA來做個示范阁吝,畢竟主要講防御
low等級的注入無過濾直接提交id
medium等級使用了mysqli_real_escape_string函數(shù)進行轉(zhuǎn)義,被轉(zhuǎn)義的包括\x00,\n,\r,\,’,”,\x1a(參考菜鳥教程)但是這種簡單的轉(zhuǎn)義很容易就被各種編碼方式繞過械拍。
high等級的代碼采用了窗口跳轉(zhuǎn)的方式突勇,但是對于上交的數(shù)據(jù)始終沒有處理就提交了,只是簡單的在其后加了一個LIMIT 1坷虑,來限制取數(shù)據(jù)的行數(shù)甲馋,但是只要簡單的使用#或者--+來注釋掉就可以了。(感覺這個應(yīng)該屬于midium)
high等級的代碼加入了token機制和PDO迄损,基本防御了SQL注入定躏。反正以我的水平和在網(wǎng)上查找的資料來看,好像沒有成功注入的芹敌。
0x02
首先大前提是驗證都處于服務(wù)器端痊远,前端的驗證形同虛設(shè)。
(1)使用PDO
PDO是PHP的一個擴展氏捞,為PHP訪問數(shù)據(jù)庫提供一個統(tǒng)一的接口碧聪,這就表明PDO可以連接不同類型的數(shù)據(jù)庫系統(tǒng),但是我們還是需要自己編寫SQL語句液茎。PDO隨PHP5.1發(fā)行逞姿,在PHP5.0的PECL擴展中也可以使用,無法運行于之前的PHP版本捆等,可以在phpinfo()中查看是否支持PDO滞造。
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');//設(shè)置編碼以防止亂碼
$sql ="SELECT id FROM user WHERE email=:email";
$stmt = $pdo->prepare($sql);
$email = filter_input(INPUT_GET,'email');
$stmt->bindValue(':email', $email);
上述代碼中,:email是具名占位符栋烤,可以安全的綁定任意值谒养。預(yù)處理語句會自動過濾$email的值,防止數(shù)據(jù)庫收到SQL注入攻擊班缎。一個sql語句字符串中可以綁定多個具名占位符蝴光,然后在預(yù)處理語句中通過bindValue()方法綁定各個占位符的值她渴。
(2)使用mysqli_query
MySQLi 擴展是在 PHP 5.0.0 版本中引進的,且只針對mysql數(shù)據(jù)庫蔑祟,但是其實大概原理和DBO相似趁耗,都是采用了prepare?+?bind?的寫法。
$mysqli?=?new?mysqli('localhost','username','password','database');??
$query?=?$mysqli->prepare('??
???SELECT?*?FROM?users??
???WHERE?username?=????
???AND?email?=????
???AND?last_login?>??');?
$query->bind_param('sss',?'test',?$mail,?time()?-?3600);??
$query->execute();
這個問號(?)綁定參數(shù)看上去很短疆虚,但是相比名稱式參數(shù)缺少了靈活性苛败,而且迫使開發(fā)者必須保證參數(shù)的順序,有時候讓人覺得很蛋疼径簿。而且不幸的是MySQLi并不支持名稱式參數(shù)罢屈。
(3)對輸入進行轉(zhuǎn)義處理
這一類主要是通過編程語言的預(yù)定義函數(shù)對輸入轉(zhuǎn)義,包括mysql_real_escape_string篇亭、addslashes()等缠捌,但是這一類函數(shù)存在一定的安全風(fēng)險,不推薦使用译蒂。參見文章:PHP防SQL注入不要再用addslashes和mysql_real_escape_string了
(4)限制輸入的內(nèi)容
這其中包括對select曼月、union等的過濾,但是這樣一方面帶來了對于用戶使用的舒適性也有可能過濾不嚴格導(dǎo)致形同虛設(shè)柔昼。
(5)對輸入編碼
//這也算是一種處理各種注入的萬能方法了哑芹,但是不足就是每次存取都需要編碼或者解密,效率可能會降低捕透。
SELECT?password?FROM?users?WHERE?name?=?'root'????????????--普通方式??
SELECT?password?FROM?users?WHERE?name?=?0x726f6f74????????--防止注入??
SELECT?password?FROM?users?WHERE?name?=?UNHEX('726f6f74')?--防止注入??
(6)使用存儲過程
存儲過程是各種數(shù)據(jù)庫的一種函數(shù)式編程方法聪姿,類似于預(yù)處理,只分配必要的數(shù)據(jù)庫許可權(quán)限乙嘀,有助于減輕SQL注入的影響——限制攻擊者只能調(diào)用存儲過程末购,從而限制了能夠訪問或修改的數(shù)據(jù)。由于SQL注入不僅能發(fā)生在應(yīng)用層乒躺,還能發(fā)生在數(shù)據(jù)庫層招盲,因此如果攻擊者將惡意語句寫入到存儲過程中,雖然訪問和修改數(shù)據(jù)受到限制嘉冒,但是如果在后續(xù)的動態(tài)SQL中使用了該輸入,仍可能造成SQL注入咆繁。
以上就是目前我能知道的所有了讳推,需要學(xué)習(xí)的還很多。FIGHTING~~~
如果誰看到我這個覺得不深入玩般,給大家推薦一篇更詳細的文章:SQL注入之代碼層防御