這種漏洞是如何出現(xiàn)的呢?簡單介紹一下,高手請飄過。
一般用戶在登陸時,系統(tǒng)會要求輸入用戶名及密碼,然后將這些數(shù)據(jù)傳輸?shù)街付摚M(jìn)行驗證,大致的代碼如下:
Set Conn= Server.CreateObject("ADODB.Connection") '定義連接數(shù)據(jù)庫的對象
Const AccessFile="jmdcw.mdb" '數(shù)據(jù)庫地址
Conn.ConnectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(AccessFile) '連接到數(shù)據(jù)庫
Conn.Open '打開數(shù)據(jù)庫
....................
name=request("name") '得到所提交的用戶名
pass=request("pass") '得到所提交來的密碼
............
Set Jmdcw=Server.CreateObject("ADODB.RecordSet") '定義操作數(shù)據(jù)庫的對象
SQL="SELECT username,userpass FROM User WHERE username='"&name&"' AND userpass='"&pass&"'" 'SQL語句
Jmdcw.Open SQL,Conn,1,1 '執(zhí)行查詢
......
If Jmdcw.EOF AND Jmdcw.BOF Then '如果沒有查詢到
response.redirect "onerror.html" '顯示錯誤頁
end if
'如果正確,就繼續(xù)執(zhí)行。
..........
以上就是一段簡單的用戶驗證代碼,當(dāng)注入漏洞被廣泛發(fā)掘之后,類似這樣的漏洞就越來越少了,但少并不表示程序員在寫代碼時已經(jīng)具備了防范意識,無意之中還是會出現(xiàn)這樣或那樣的漏洞。OK,書歸正傳,先來測試一下上面的代碼。輸入的用戶名是:jmdcw,密碼是:123456。(典型的弱口令密碼,哈哈),這樣SQL語句就是:
select username,userpass from user where username='jmdcw' and userpass='123456'
程序會查詢user表中是否有jmdcw用戶,并且該用戶的密碼是否為123456。如果username='jmdcw'的結(jié)果為真, userpass='123456'的結(jié)果也為真,那么“真 And 真 ”的結(jié)果就是真,驗證通過。
當(dāng)然,如果用戶名和密碼其中之一的結(jié)果為假,“真 And 假 ”的結(jié)果就是假,當(dāng)然“ 假 And 假 ”的結(jié)果也是假,呵呵。
沒有用戶名或密碼怎么進(jìn)入?試一下'or''='吧,在提交用戶名處輸入 jmdcw'or''=',這樣的SQL語句就是
select username,userpass from user where username='jmdcw'or''='' and userpass='12345678'
在邏輯表達(dá)式中,AND的優(yōu)先級要高于OR,所以語句會先對 “''='' and userpass='12345678'” 進(jìn)行判斷,雖然 ''='' 為真,但密碼為假,所以結(jié)果為假,但因為我們加入了OR連接符,這樣,雖然后面的結(jié)果為假,但username的結(jié)果為真,所以也一樣能進(jìn)入這個用戶的后臺。
但如果不知道用戶的名稱,那么就要在輸入的密碼后也加入一個'or''=',這樣,SQL語句就是
select username,userpass from user where username='jmdcw11'or''='' and userpass='12345678'or''=''
在執(zhí)行and語句,''='' and userpass='12345678'的結(jié)果為假,然后是 'jmdcw11'or假 ,結(jié)果為假,再接下來是:假or ''='',這個結(jié)果就是真了。
但現(xiàn)在的密碼都用MD5加密,對提交來的密碼在進(jìn)入SQL語句之前,先用MD5進(jìn)行了轉(zhuǎn)換,這樣,就算在密碼后加入了'or''=',也發(fā)揮不了作用。對于密碼采用md5加密的,不妨在用戶名處再加入一個or''='',也 就是在用戶名處輸入:jmdcw'or''=''or''=',這樣的SQL 語句就是:
select username,userpass from user where username='jmdcw11'or''=''or''='' and userpass='12345678'
先執(zhí)行and語句,結(jié)果為假,然后是username='jmdcw11'or''='',結(jié)果為真,接下來是:真or假,結(jié)果還是真,這樣又繞過了驗證。
說到這兒,我忽然想起,在文章開頭所提到的網(wǎng)站,其密碼也是用md5加密的,并且我也不知道任何一個用戶名,也只用了一個or語句,為什么卻進(jìn)入了呢?思來思去,莫不是SQL語句中的用戶與密碼的位置有所不同,其的SQL語句是這樣的:
select username,userpass from user where WHERE userpass='"&pass&"'" and username='"&name&"',
密碼在前面,用戶在后面,這樣,當(dāng)我在用戶名處輸入:jm'or''='后,其語句就變成了
select username,userpass from user where WHERE userpass='123456" and username='jm'or''=''
按照優(yōu)先級,先運(yùn)算ANd語句,結(jié)果為假,然后是OR語句,假or''='',結(jié)果就是真了?磥泶a中的位置發(fā)生變化也能演繹成一種漏洞。
上面所提到的方法主要是針對于ACCESS數(shù)據(jù)庫,但如果程序所對應(yīng)的數(shù)據(jù)庫是SQL,那危害就大很了,先不要說別的,還是說一下登陸的事情,直接用:
存在的用戶名';--
這個可以不用密碼就登陸到指定的用戶之中,如果不知道呢:就用:
任意名稱'or''='';--
這樣所進(jìn)入的會是第一個用戶,很有可能是管理員的用戶之中.
如何防止這種漏洞呢?很簡單,就是在接收字符的語句中加入replace過濾語句,比如name就是:
name=replace(request("name"),"'","")
將'過濾為空。密碼過濾的方法也類似。當(dāng)然,這是簡單的過濾方法,還有更多復(fù)雜的。比如過濾一些特殊字符,空格、chr(0)、%、script等一些字符,防止寫入XSS代碼。