SQL注入防御與繞過(guò)的幾種姿勢(shì)
前言
本文章主要以后端PHP和MySQL數(shù)據(jù)庫(kù)為例,參考了多篇文章后的集合性文章,歡迎大家提出個(gè)人見(jiàn)解,互促成長(zhǎng)。
一、 PHP幾種防御姿勢(shì)
1. 關(guān)閉錯(cuò)誤提示
說(shuō)明:
PHP配置文件php.ini中的display_errors=Off,這樣就關(guān)閉了錯(cuò)誤提示。
2. 魔術(shù)引號(hào)
說(shuō)明:
當(dāng)php.ini里的magic_quotes_gpc=On時(shí)。提交的變量中所有的單引號(hào)(')、雙引號(hào)(")、反斜線(\)與 NUL(NULL 字符)會(huì)自動(dòng)轉(zhuǎn)為含有反斜線的轉(zhuǎn)義字符。
魔術(shù)引號(hào)(Magic Quote)是一個(gè)自動(dòng)將進(jìn)入 PHP 腳本的數(shù)據(jù)進(jìn)行轉(zhuǎn)義的過(guò)程。(對(duì)所有的 GET、POST 和 COOKIE 數(shù)據(jù)自動(dòng)運(yùn)行轉(zhuǎn)義)
PHP 5.4 之前 PHP 指令 magic_quotes_gpc 默認(rèn)是 on。
本特性已自PHP 5.3.0 起廢棄并將自 PHP 5.4.0 起移除,在PHP 5.4.O 起將始終返回 FALSE。
參考:
《magic_quotes_gpc相關(guān)說(shuō)明》:
http://www.cnblogs.com/qiantuwuliang/archive/2009/11/12/1601974.html
3. addslashes
說(shuō)明:
addslashes函數(shù),它會(huì)在指定的預(yù)定義字符前添加反斜杠轉(zhuǎn)義,這些預(yù)定義的字符是:?jiǎn)我?hào)(')、雙引號(hào)(")、反斜線(\)與 NUL(NULL 字符)。
這個(gè)函數(shù)的作用和magic_quotes_gpc一樣。所以一般用addslashes前會(huì)檢查是否開了magic_quotes_gpc。
magic_quotes_gpc與addslashes的區(qū)別用法:
1)對(duì)于magic_quotes_gpc=on的情況
我們可以不對(duì)輸入和輸出數(shù)據(jù)庫(kù)的字符串?dāng)?shù)據(jù)作addslashes()和stripslashes()的操作,數(shù)據(jù)也會(huì)正常顯示。
如果此時(shí)你對(duì)輸入的數(shù)據(jù)作了addslashes()處理,那么在輸出的時(shí)候就必須使用stripslashes()去掉多余的反斜杠。
2)對(duì)于magic_quotes_gpc=off 的情況
必須使用addslashes()對(duì)輸入數(shù)據(jù)進(jìn)行處理,但并不需要使用stripslashes()格式化輸出,
因?yàn)閍ddslashes()并未將反斜杠一起寫入數(shù)據(jù)庫(kù),只是幫助mysql完成了sql語(yǔ)句的執(zhí)行。
參考:
《addslashes函數(shù)說(shuō)明》:
https://secure.php.net/manual/zh/function.addslashes.php
《對(duì)于magic_quotes_gpc的一點(diǎn)認(rèn)識(shí)》:
http://www.phpfans.net/bbs/viewthread.php?tid=6860&page=1&extra=page=1
4. mysql_real_escape_string
說(shuō)明:
mysql_real_escape_string()函數(shù)轉(zhuǎn)義 SQL 語(yǔ)句中使用的字符串中的特殊字符。
下列字符受影響:
- \x00
- \n
- \r
- \
- '
- "
- \x1a
如果成功,則該函數(shù)返回被轉(zhuǎn)義的字符串。如果失敗,則返回 false。
本擴(kuò)展自 PHP5.5.0 起已廢棄,并在自 PHP 7.0.0 開始被移除。
因?yàn)橥耆詥?wèn)題,建議使用擁有Prepared Statement機(jī)制的PDO和MYSQLi來(lái)代替mysql_query,使用的是mysqli_real_escape_string
參考:
《 PHP防SQL注入不要再用addslashes和mysql_real_escape_string了》:
http://blog.csdn.net/hornedreaper1988/article/details/43520257
《PDO防注入原理分析以及使用PDO的注意事項(xiàng)》:
http://zhangxugg-163-com.iteye.com/blog/1835721
5. htmlspecialchars()
說(shuō)明:
htmlspecialchars()函數(shù)把預(yù)定義的字符轉(zhuǎn)換為 HTML實(shí)體。
預(yù)定義的字符是:
- & (和號(hào))成為 &
- " (雙引號(hào))成為 "
- ' (單引號(hào))成為 '
- < (小于)成為 <
- > (大于)成為 >
6. 用正則匹配替換來(lái)過(guò)濾指定的字符
- preg_match
- preg_match_all()
- preg_replace
參考:
《preg_match說(shuō)明》:
http://php.net/manual/zh/function.preg-match.php
《preg_replace說(shuō)明》:
https://secure.php.net/manual/zh/function.preg-replace.php
7. 轉(zhuǎn)換數(shù)據(jù)類型
說(shuō)明:
根據(jù)「檢查數(shù)據(jù)類型」的原則,查詢之前要將輸入數(shù)據(jù)轉(zhuǎn)換為相應(yīng)類型,如uid都應(yīng)該經(jīng)過(guò)intval函數(shù)格式為int型。
8. 使用預(yù)編譯語(yǔ)句
說(shuō)明:
綁定變量使用預(yù)編譯語(yǔ)句是預(yù)防SQL注入的最佳方式,因?yàn)槭褂妙A(yù)編譯的SQL語(yǔ)句語(yǔ)義不會(huì)發(fā)生改變,在SQL語(yǔ)句中,變量用問(wèn)號(hào)?表示,攻擊者無(wú)法改變SQL語(yǔ)句的結(jié)構(gòu),從根本上杜絕了SQL注入攻擊的發(fā)生。
代碼示例:
參考:
《Web安全之SQL注入攻擊技巧與防范》:
http://www.plhwin.com/2014/06/13/web-security-sql/
二、 幾種繞過(guò)姿勢(shì)
下面列舉幾個(gè)防御與繞過(guò)的例子:
例子1:addslashes
防御:
這里用了addslashes轉(zhuǎn)義。
繞過(guò):
- 將字符串轉(zhuǎn)為16進(jìn)制編碼數(shù)據(jù)或使用char函數(shù)(十進(jìn)制)進(jìn)行轉(zhuǎn)化(因?yàn)閿?shù)據(jù)庫(kù)會(huì)自動(dòng)把16進(jìn)制轉(zhuǎn)化)
- 用注釋符去掉輸入密碼部分如“-- /* #”
payload:
- http://localhost/injection/user.php?username=admin-- hack
(因?yàn)橛械腟QL要求--后要有空格,所以此處加上了hack)
- http://localhost/injection/user.php?username=admin/*
(escape不轉(zhuǎn)義/*)
- http://localhost/injection/user.php?username=admin%23
(這里的%23即為#,注釋掉后面的密碼部分。注意IE瀏覽器會(huì)將#轉(zhuǎn)換為空)
- http://localhost/injection/user.php?username=0x61646d696e23
(admin# -->0x61646d696e23)
- http://localhost/injection/user.php?username=CHAR(97,100, 109, 105, 110, 35)
(admin# -->CHAR(97, 100, 109, 105, 110, 35))
關(guān)于編碼原理:
因?yàn)橐话闱岸薐avaScript都會(huì)escape()、encodeURL或encodeURIComponent編碼再傳輸給服務(wù)器,主要為encodeURL,如下,所以可以利用這點(diǎn)。
JavaScript代碼如:
攔截請(qǐng)求:
1)escape( )
對(duì)ASCII字母、數(shù)字、標(biāo)點(diǎn)符號(hào)"@* _ + - . /"不進(jìn)行編碼。在\u0000到\u00ff之間的符號(hào)被轉(zhuǎn)成%xx的形式,其余符號(hào)被轉(zhuǎn)成%uxxxx的形式。(注意escape()不對(duì)"+"編碼,而平時(shí)表單中的空格會(huì)變成+)
2) encodeURL
對(duì)" ; / ? : @ & = + $ , # ' "不進(jìn)行編碼。編碼后,它輸出符號(hào)的utf-8形式,并且在每個(gè)字節(jié)前加上%。
3) encodeURIComponent
用于對(duì)URL的組成部分進(jìn)行個(gè)別編碼,而不用于對(duì)整個(gè)URL進(jìn)行編碼。
常用編碼:
- @ * _ + - ./ ; \ ? : @ & = + $ , # ' 空格
轉(zhuǎn)碼工具可用:
參考:
《URL編碼》:
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
例子2:匹配過(guò)濾
防御:
繞過(guò):
關(guān)鍵詞and,or常被用做簡(jiǎn)單測(cè)試網(wǎng)站是否容易進(jìn)行注入攻擊。這里給出簡(jiǎn)單的繞過(guò)使用&&,||分別替換and,or。
- 過(guò)濾注入: 1 or 1 = 1 1 and 1 = 1
- 繞過(guò)注入: 1 || 1 = 1 1 && 1 = 1
關(guān)于preg_match過(guò)濾可以看參考文章,文章里講得很詳細(xì)了。
參考:
《高級(jí)SQL注入:混淆和繞過(guò)》:
http://www.cnblogs.com/croot/p/3450262.html
例子3:strstr
防御:
strstr ()查找字符串的首次出現(xiàn),該函數(shù)區(qū)分大小寫。如果想要不區(qū)分大小寫,使用stristr()。(注意后面這個(gè)函數(shù)多了個(gè)i)
繞過(guò):
strstr()函數(shù)是對(duì)大小寫敏感的,所以我們可以通過(guò)大小寫變種來(lái)繞過(guò)
payload:
- http://localhost/injection/user.php?id=1uNion select null,null,null
例子4:空格過(guò)濾
防御:
繞過(guò):
1)使用內(nèi)聯(lián)注釋。
2)使用換行符代替空格。注意服務(wù)器若為Windows則換行符為%0A%0D,Linux則為%0A。
- http://localhost/injection/user.php?id=1/**/and/**/11=1
- http://localhost/injection/user.php?id=1%0A%0Dand%0A%0D1=1
例子5:空字節(jié)
通常的輸入過(guò)濾器都是在應(yīng)用程序之外的代碼實(shí)現(xiàn)的。比如入侵檢測(cè)系統(tǒng)(IDS),這些系統(tǒng)一般是由原生編程語(yǔ)言開發(fā)而成,比如C++,為什么空字節(jié)能起作用呢,就是因?yàn)樵谠兂烧Z(yǔ)言中,根據(jù)字符串起始位置到第一個(gè)出現(xiàn)空字節(jié)的位置來(lái)確定字符串長(zhǎng)度。所以說(shuō)空字節(jié)就有效的終止了字符串。
繞過(guò):
只需要在過(guò)濾器阻止的字符串前面提供一個(gè)采用URL編碼的空字節(jié)即可。
payload:
例子6:構(gòu)造故意過(guò)濾
防御:
繞過(guò):
文件的63行開始可以看到,此處將傳入的%27和%2527都進(jìn)行刪除處理,也就是還沒(méi)傳入數(shù)據(jù)庫(kù)前就已經(jīng)被該死的程序吃了,但是在67行看到他還吃了*,這樣我們就有辦法了,我們構(gòu)造%*27,這樣程序吃掉星號(hào)*后,%27就會(huì)被傳入。
payload:
- http://localhost/injection/user.php?id%3D1%*27%*20and%*20%*271%*27%3D%*271
(id=1' and '1'='1-->id%3D1%*27%*20and%*20%*271%*27%3D%*271)
參考:
《phpcms_v9.6.0_sql注入與exp》: