所謂的SQL注入、XSS、溢出等的漏洞,歸根到底,就是代碼注入的問題,導致代碼注入漏洞的產生的原因是因爲代碼和數據沒有分離,即程序所處理的數據和程序的代碼混在了一起,沒有明確的區分。。。$oM>?h_
=
ok:L]8UN
3
而SQL注入產生的主要原因也就是用戶所提交的數據被當作代碼來執行,請看下面這個獲取文章內容例子(省略了部分代碼):$id=
$_GET["ID"];$sql = ‘SELECT * FROM article WHEREID=’.$id;$mysqli->multi_query($sql);?>注意看,當我們要查看這個某個文章的時候,就提交這個文章的ID(一般的網站對於這種請求都是使用GET請求的,即用戶可輕易在URL上修改請求的內容。如果是POST請求的,可通過抓包改包或是修改網頁內容進行修改請求),就會把SQL語句中的$ID變量賦值爲當前用戶提交的數據進行SQL查詢。例如:當用戶查看一篇ID爲3的文章,那麼此時的URL爲X=abaKl
http://www.xxx.com/article.php?ID=3;k+?gWZ
\
o3|4PAA/
此時服務器$_GET["ID"]所得的值就是3了。在經過SQL語句拼接之後,所得的SQL語句就變爲Ri_2@
U-
SELECT * FROM article WHERE ID=3;@MTv4eC}e
D84&=EpVZ
當然,這個是程序員所期望的實現的,但黑闊們看到的不是功能,而是漏洞!!o@.{|j
%dW
;P[0
因爲存在SQL注入漏洞的關鍵條件是SQL語句拼接了用戶能控制的變量,這個條件,在以上的例子中就符合了,所以黑闊完全可以提交惡意SQL語句與原請求的內容拼接成一個程序員完全沒想到的惡意SQL語句提交給數據庫引擎去執行。。。
R6fkc^
aZ_3@I{d`
假設黑闊在原本的URL後增加如下的語句: Nr$78]o9
;DROP TABLE admin–即原本的URL變爲:http://www.xxx.com/article.php?ID=3;DROPTABLE admin–注意,$_GET["ID"]此事的值就不再是3了,而是3;DROP TABLE admin–了。那拼接後的SQL語句會是怎樣的呢?!那就是:SELECT * FROM articleWHERE ID=3;DROP TABLE admin–Y7p@NG&1q
3~3tjhw;]9
好了,那我們來分析一下這個SQL語句。。。K/N{F\
,C><n kx
首先,會執行:SELECT * FROM article WHERE ID=3,這是一個正常的SQL語句吧?!,是查詢文章的內容的。問題是,執行完這個之後,會再執行:DROP TABLE admin 而這個就是一個惡意的SQL語句了,它的作用是刪除admin這個表,這樣就導致數據庫的數據丟失了,是一個非常危險的語句,同樣的,我也可以刪除article這個表,導致此網站所有的文章丟失!!很邪惡吧?!!當然,現在用multi_query函數的也比較少了,大多數都是用mysql_query函數,但別以爲這樣就可以防止SQL注入,因爲提交的數據還是被拼接到了SQL語句中,只要構造好惡意的SQL語句,進行SQL注入也是輕而易舉的。例如:在原本URL後加入 order by X(X是數字),就可以猜字段數,另外還可以加Union語句也可以做到語句的拼接進行攻擊(需要SQL引擎版本的支持,Access數據庫不支持),具體的一些攻擊技巧,大家可以Google或百度一下,這方面的資料很多,我也沒必要展開講。。。 這也是一個典型的SQL注入的例子,但是現實中,有一大部分小白程序員都會寫出這樣明顯的漏洞代碼!!(注意這個語句後面的–,這是MYSQL語句中的註釋,用於註釋掉後面的內容,避免語句執行錯誤,因爲黑闊一般情況下是不能準確的知道你的SQL語句的結構的)
$"|r7n5[
k]r4b`x`
但是一般的黑闊是不會做這些的,因爲做這些對他們自己沒有任何益處,他們大部分的目的不是刪除你網站的數據,而是要拿到這個網站的shell甚至是服務器權限。所以,他們通常會利用SQL注入去構造惡意語句來獲取WEB管理員的後臺帳號和密碼,然後去登陸後臺,進行進一步的滲透(如果數據庫用戶的權限足夠高,黑闊可以直接獲取系統權限),這裏就不擴展了,有興趣的童鞋可以Google或百度一下,這方面的資料也是很多的,咱們論壇也有不少。。。.|go$}Fk
再來看一個很經典的SQL注入例子,那就是萬能密碼。或許有些人會覺得,萬能密碼的問題怎麼和SQL注入扯一起了呢?!事實上,出現萬能密碼這種漏洞,本質就是SQL注入,這在 代碼注入(番外篇)上已經總結過了,我就不再總結了,直接複製過來吧。。。N1c
0
>{
FA{Q6fi:2
看產生萬能密碼的漏洞代碼:e_|<tYx‑><
f9>pMfi:@
$username = $_POST["username"]; X=m^+%iD
$password = $_POST["password"]; H3R{+7
$result = mysql_query(“SELECT * FROM Users where UserName=’$username’ andPassWord=’$password’”);9%NsW3
|
if(mysql_num_rows( $result ) > 0){echo ‘alert(“login is true!”);5&EBU
l}
window.location = “index.php”’;}qQDe'f~
[D
eD‑U:
當黑闊提交 ‘or 1=1– (萬能密碼)的時候,提交的內容被注入到SQL語句中,這時候有幾種情況,這裏列舉兩個:_)= e`9%
1. 當黑闊猜測用戶名爲admin,密碼提交萬能密碼的時候,SQL語句變爲:j~ds)dW%`&
SELECT * FROM Users where UserName=’admin’ and PassWord=”or 1=1–’2Ul8<${c{
>S}‑X)4
此時,where限定的是 UserName內容爲admin,PassWord爲空才進行返回(這兩個限定條件用and連接),但是注意後面有一個or 1=1。;Krs*3 s
O-p`9(_m
通過邏輯的處理,我們知道這個限定條件的意思是:當UserName爲admin和PassWord爲空或者1=1時就進行返回查詢信息e&i`/m5
fP4P'e‑I
所以關鍵就是or這個邏輯,導致前面的限定都行爲虛設。 9Ca0Tu
1QmOUw}yj
至於or 1=1後面–,在SQL語句中,–爲註釋,也就是註釋掉最後的’,避免執行語句錯誤;/4x.t#b
X0j>g^b8
最後返回給 $result變量的是Users表的內容,然後就進行判斷$result的數組是否爲零,如果大於零,則認爲是登陸成功Ue;Z)}
V73/q
因爲Users表中已經有用戶了,所以返回的數組肯定不爲空,所以肯定可以登陸,代碼如下:if(mysql_num_rows($result ) > 0){echo ‘alert(“login is true!”);window.location =“index.php”’;}最後就登陸成功的~ ~e,l2
<
‑"S'
Yn-
2. 當黑闊提交用戶名和密碼都爲萬能密碼(’or 1=1–)的時候與1中類似,SQL語句變爲如下:tXrKC
vmNI$
KZM
SELECT * FROM Users where UserName=”or 1=1–’ and PassWord=”or 1=1–’與1中不同的是,–符號在UserName中就出現了,所以後面的語句已經被忽略了 oBub]<.J
wS,fj gX
SQL語句的邏輯變爲:當UserName爲空或者 1=1時就進行返回查詢信息然後與1中一樣,返回了Users表中的內容給$result變量,再進行判斷,然後就登陸成功了。。。*v8daF
l\N2C‑4NG
這裏講了兩個SQL注入的例子,或許你以爲SQL注入只存在於WEB端,對服務器沒有直接的影響,但如果你這樣想,那就錯了!! 如果權限處理不當,一個SQL注入點就可以直接導出Shell,甚至是在服務器上執行任意命令!!而據我所知,這些權限處理不當的服務器在互聯網中也不佔少數,所以希望各位程序猿、網站管理員等的引起足夠的重視!!rrgOp5aV"
^a/q6{
好了,上面已經分析了SQL注入產生的原因,那下面就講如何防禦了! &k_L
K
PvW4%A@0
SQL注入是一個發現於1998年,可以說是屬於上世紀的漏洞了,但現在仍然有不少的網站存在着這樣的漏洞,是這種漏洞很難防禦嗎?!!lJfk4 -;M
BaP'y8dVN
答案是否定的,從理論上來說,只要防禦方式恰當,SQL注入是可以杜絕的。而我們要防禦SQL注入,要做的事就是先把所有可能存在SQL注入的地方都找出來,然後逐個修復,切忌不能因爲覺得某個注入點難以挖掘而忽視不管,這樣你就輕視了黑闊了!一旦這個注入點被挖掘,你之前做的所有工作都可以說是白費了,這也是平常我們所說的“木桶原理”。4=y&}3om(0
|XN w&X1VF
防禦SQL注入的要點:1.不要信任任何用戶提交的數據2.使用白名單原則進行過濾,黑名單不靠譜,這也是做安全所必須知道的3.SQL語句要儘量避免使用字符串拼接的形式,強烈建議使用查詢參數化(綁定變量)的方法進行查詢4.數據庫應遵循“最小權限”原則5.數據類型檢測,不同數據類型進行不同的過濾對於第一點,準確來說是:任何經過了客戶端的數據都不能信任,因爲黑闊還可以通過抓包改包的方法修改一些瀏覽器不能修改的數據,而這些也是程序猿經常忽略的地方!!對於第二點,採用白名單而不用黑名單,這是我在刺總的《白帽子講WEB安全》上覺得收穫最大的一個思想,也是安全圈子的常識了!! 因爲黑名單原則在無數的例子前面已經突出了它明顯的不足之處。例如,過濾一處SQL注入點,採用黑名單過濾了and這個SQL保留字,但我可以把and改爲aNd來繞過過濾機制。可能你會說,那我把所有的可能都過濾了,不就行了?!對於這個想法,第一,工作量非常大,而且容易遺漏;9qGba=}Ey
jHHCJOHB8
第二,隨着數據庫版本的更新,可能會出現一些新的保留字,而你又不能及時的過濾,就可能造成悲劇滴發生。。。所以,能不用黑名單過濾就儘量避免! =\5f_g2M
H13\8Te{
對於第三點,上面的兩個例子都已經說明SQL語句使用字符串拼接的方法很可能會造成SQL注入的發生了,所以我們要儘量避免使用這樣的字符串拼接的方式。。。這裏強烈建議使用查詢參數化(綁定變量)的方法進行查詢,這也是刺總所推薦解決SQL注入的方法。。。 從安全的角度來說,查詢參數化有效解決SQL注入的問題;從開發的角度來說,還可以提高SQL查詢的性能,可以說是一舉兩得的方法。。。GCr]x '
x)$0Nr62D
對於第四點,其實做安全時,任何涉及到權限的問題時,都應該遵循這個“最小權限”原則。即只要給程序所需的權限即可,多餘的權限都CUT掉,這樣就可以防止一些因爲權限過大所出現的安全問題,就例如上面說提到的,利用SQL注入e~'z;%
O~
Q3
bU"f
導出Shell甚至在服務器執行任意命令。。。對於第五點,可能很多程序猿都有這麼一個誤區,就是隻要對用戶提交的數據進行mysql_real_escape_string()或是addslashes()處理就可以進行安全的SQL查詢了(包括一些專業的文檔也這麼說)。。。f2Xn!]o
- 3PLP$P
那我們來看下mysql_real_escape_string()會對哪些字符進行轉義: ’ ” \r \n NULL Control-Z上面列舉的是mysql_real_escape_string()會進行轉義的(addslashes()就不進行討論了,因爲addslashes()轉義的比這個函數還要少),那來看下刺總在他書上舉的一個例子:http://www.xxx.com/user.php?id=12,AND,1=0,union,select,1,concat(user,0x3a,password),3,4,5,6,from,mysql.user=substring_index(current_user(),char(64),1)以上這個例子就沒用到 mysql_real_escape_string()轉義的字符吧!!所以對於這種數值型的參數,不能用mysql_real_escape_string()進行轉義,應該用intval()或是settype()進行數據類型的限定(當然這裏說的是不用預編譯的方法來進行SQL查詢),其他的也是類似,但預防SQL注入不能單單靠數據類型的檢測,還應該結合以上的一些方案好了,對於《WEB攻防系列之SQL注入》就告一段落了!