1.關(guān)于交互式動態(tài)網(wǎng)頁可能存在的問題 1.1 form類型的交互 1.1.1 概念介紹 在我們和瀏覽者進(jìn)行交互時,最常用到的就是form(post/get/put方法),雖然非常方便,但是很多問題也是因他而起。 form表單中input標(biāo)志 用來接受用戶輸入的信息,例如:用戶名、密碼、email等。如果你沒有對用戶輸入進(jìn)行很好的檢查的話,一個惡意的用戶會屏蔽掉一些安全機(jī)制,繞過安全認(rèn)證。例如,輸入標(biāo)準(zhǔn)的HTML語句或者javascript語句會改變輸出結(jié)果 ,在輸入框中打入標(biāo)準(zhǔn)的HTML語句會得到什么樣的結(jié)果呢?比如一個留言本,我們留言內(nèi)容中打入:<font size=10>你好!</font> 如果你的程序中沒有屏蔽html語句,那么就會改變"你好"字體的大小。在留言本中改變字體大小和貼圖有時并不是什么壞事,反而可以使留言本生動。但是如果在輸入框中寫個 Javascript 的死循環(huán),比如: <a herf="http://someurl" onMouSEOver="while(1) {window.close('/')}">第一萬個驚心動魄</a> 那么其他查看該留言的客人只要移 動鼠標(biāo)到"第一萬個驚心動魄",上就會使用戶的瀏覽器因死循環(huán)而死掉。 1.1.2 防范要點(diǎn) (1)對特殊字符進(jìn)行過濾 ([/&;/`'///|"*?~<>^/(/)/[/]/{/}/$/n/r])///$1/g;),這個是最基本的,在很多地方也已經(jīng)不只一次提到過 <script language="vbscript"> sub uBotton_onclick if form1.uUserName.value=""then msgbox"您的姓名不能為空!",0+32,"哦!還不行" form1.uUserName.focus exit sub end if
if form1.uPassWord.value=""then msgbox"您的密碼不能為空!",0+32,"哦!還不行" form1.uPassword.focus exit sub end if
if form1.uUserName.value=""then msgbox"您的姓名不能為空!",0+32,"哦!還不行" form1.uUserName.focus exit sub end if form1.submit end sub </script>
function isEmpty(objname) { var str = document.inputform[objname].value var tmpstr = str.replace([/&;/`'///|"*?~<>^/(/)/[/]/{/}/$/n/r])///$1/g;,"") var tmpstr = tmpstr.replace([/&;/`'///|"*?~<>^/(/)/[/]/{/}/$/n/r])///$1/g;,"") return (tmpstr.length==0) }
function check() { tf=document.inputform errors="" if (isEmpty("username")) errors += "用戶名不能為空。/n"; if (isEmpty("password")) errors += "密碼不能為空!/n" if (errors!="") alert(errors); return (errors=="") } (2) 對輸入的字符長度進(jìn)行限制 (3) 進(jìn)行盡可能多的錯誤出理和錯誤陷阱 (4) 盡可能多的使用以下這些標(biāo)志,減少用戶輸入的機(jī)會 <input type="checkbox" name="checkbox" value="checkbox"> <select name="select"> </select> <input type="radio" name="radiobutton" value="radiobutton">
<!--#include file="conn.asp"--> <% dim errmsg if request.form("username")="" then ErrMsg="用戶名不能為空" foundError=True else UserName=request.form("UserName") end if
if request.form("password")="" then ErrMsg="密碼不能為空" foundError=True else PassWord=request.form("PassWord") end if if FoundError=true then showAnnounce(ErrMsg) else set rstmp=server.createobject("adodb.recordset") if Request.ServerVariables("REQUEST_METHOD") = "POST" then rstmp.open "Select * from User Where userName='" & UserName & "'",conn,3,3 if rstmp.bof then session.contents("UserName")=UserName rstmp.addnew rstmp("username")=username rstmp("userpassword")=password rstmp("logins")=1 rstmp("online")=1 rstmp.update response.redirect("index.asp") elseif PassWord<>rstmp("userpassword") then ErrMsg="密碼錯啦" foundError=True showAnnounce(ErrMsg) else session.contents("UserName")=UserName rstmp("logins")=rstmp("logins")+1 rstmp("online")=1 rstmp.update rstmp.close Set rstmp=nothing response.redirect("index.asp") end if
else if session.contents("UserName")<>"" then rstmp.open "Select * from User Where userName='"&session.contents("UserName")&"'",conn,3,3 rstmp("logins")=rstmp("logins")+1 rstmp("online")=1 rstmp.update rstmp.close Set rstmp=nothing conn.close set conn=nothing response.redirect("index.asp") end if end if end if %> <html>
if adname="" then response.redirect "login.asp" end if if passwd="" then response.redirect "login.asp" end if
if adname="focus-admin" and passwd="1" then response.redirect "manage.asp" else response.redirect "login.asp" end if %> ###---checklogin.asp----end ###---manage.asp <%
dim where dim where1 dim refererURL dim refererURL2 dim refererURL3 refererURL=phyURL&"login.as" refererURL2=phyURL&"edit.asp" refererURL3=phyURL&"manage.a" refererURL4=phyURL&"savearti" where=Request.ServerVariables("HTTP_REFERER") where=left(where,(len(phyURL)+8)) if where<>refererURL and where<> refererURL2 and where<>refererURL3 and where<>refererURL4 then Response.Redirect "login.asp" end if
const MaxPerPage=20 dim totalPut dim CurrentPage dim TotalPages dim i,j
if not isempty(request("page")) then currentPage=cint(request("page")) else currentPage=1 end if
I. setcookie內(nèi)容必須完整包含帳號密碼,或類似的完整安全信息,如果只攜帶帳號信息或用某種權(quán)限標(biāo)志來認(rèn)證,極容易造成非法入侵。 例如某站點(diǎn)中的會員更新頁面中攜帶的認(rèn)證信息是兩個,用戶名和Uid(均為明文傳送)已知Uid對于每個會員是唯一的。由于我們只需要知道對方的帳號和Uid就可以更改對方信息(不需要知道密碼!),只要攻擊者知道Uid(攻擊者可以通過暴力猜測的方法來得到Uid,有時候站點(diǎn)本身也會泄露用戶的Uid,例如在論壇等處)那么,攻擊者就可以通過遍歷攻擊完成對任意一個帳號的信息更改。
II. 必須所有需要權(quán)限操作的頁面都必須執(zhí)行認(rèn)證判斷的操作。如果任何一頁沒有進(jìn)行這種認(rèn)證判斷,都有可能給攻擊者以惡意入侵的機(jī)會。
III. 很多網(wǎng)站為了方便,將用戶名以及口令信息儲存在Cookie中,有的甚至以明文方式保存口令。如果攻擊者可以訪問到用戶的主機(jī),就可能通過保存的Cookie文件得到用戶名和口令。
4 .實(shí)例說明 下面這個例子是在網(wǎng)上經(jīng)常被提到的,這是個非常經(jīng)典的例子,所以在這里通過這個實(shí)例告訴大家可能存在的危險。問題描述: 大部分網(wǎng)站把密碼放到數(shù)據(jù)庫中,在登陸驗(yàn)證中用以下sql,(以asp為例) sql="select * from user where username='"&username&"'and pass='"& pass &'" 此時,您只要根據(jù)sql構(gòu)造一個特殊的用戶名和密碼,如:ben' or '1'='1 就可以進(jìn)入本來你沒有特權(quán)的頁面。再來看看上面那個語句吧: sql="select * from user where username='"&username&"'and pass='"& pass&'" 此時,您只要根據(jù)sql構(gòu)造一個特殊的用戶名和密碼,如:ben' or '1'='1 這樣,程序?qū)兂蛇@樣: sql="select*from username where username="&ben'or'1'=1&"and pass="&pass&" or 是一個邏輯運(yùn)算符,作用是在判斷兩個條件的時候,只要其中一個條件成立,那么等式將會成立.而在語言中,是以1來代表真的(成立).那么在這行語句中,原語句的"and"驗(yàn)證將不再繼續(xù),而因?yàn)?quot;1=1"和"or"令語句返回為真值.。
另外我們也可以構(gòu)造以下的用戶名: username='aa' or username<>'aa' pass='aa' or pass<>'aa' 相應(yīng)的在瀏覽器端的用戶名框內(nèi)寫入:aa' or username<>'aa 口令框內(nèi)寫入:aa' or pass<>'aa,注意這兩個字符串 兩頭是沒有'的。這 樣就可以成功的騙過系統(tǒng)而進(jìn)入。
具體實(shí)施是這樣的,首先我會到注冊的地方去收集信息,了解盡可能多的信息,例如目標(biāo)數(shù)據(jù)庫中都有用戶的什么樣的信息,隨便的填寫信息然后提交,當(dāng)你要注冊的用戶名被注冊的是有系統(tǒng)會提示你已被注冊,有的網(wǎng)站做的更好的,就是他們專門給你設(shè)置的檢測是否有已經(jīng)被注冊的功能,通過這樣就會非常容易的找到目標(biāo)--那個提示已被注冊的用戶,讓后你在這個注冊頁里填寫一些特殊的字符,如',/,,等字符看系統(tǒng)如何提示,以證明程序員是否注意到了應(yīng)該過濾字符或懂得是否應(yīng)該過濾那些字符,在這頁進(jìn)行嘗試是因?yàn)橛械木W(wǎng)站在登錄的時候他會記錄你的ip地址,當(dāng)然你也可以找一個比你直接登錄要快的代理服務(wù)器來做跳板。后面你要做的就是察看登錄頁的html源代碼,看看是否有在客戶端的字符過濾,看看這個程序員是用什么風(fēng)格來編寫程序,盡可能多的了解程序編寫風(fēng)格,這對你以后的某些判斷有好處。如果有在客戶端的過濾也不怕,你要搞清是什么樣的過濾,能不能對攻擊造成威脅,不要一看有過濾就害怕,可以嘗試著用別的方法繞,就是使用自己精心打造的獨(dú)立腳本,進(jìn)行攻擊。然后你要看看form的action中的url是否可以直接提交,在瀏覽器地址欄里直接提交,看看返回什么,是否有來路檢測。還有很多細(xì)小的地方,你也應(yīng)該可以注意到,例如那些地方程序員的整體的編寫風(fēng)格是什么,變量名定義的風(fēng)格是什么等等,這個會幫我們"猜"到很多東西。還有別的其他什么,我也記不太清楚了,臨場發(fā)揮吧。通過這些了解我們有如下幾種可能: 1.那個程序員非常善良相信全世界都是好人,什么都沒做,根本沒有任何檢測機(jī)制,我們直接用username='aa' or username<>'aa', pass='aa' or pass<>'aa'就可以搞定,現(xiàn)在這么善良的人少啦,可是你要是有耐心,找到這種人還是不難的。 2.這個程序員可能聽別人提起過一些安全問題,畢竟現(xiàn)在這個那里都有人說,很多書中都有提及,但是做得不夠好,他只進(jìn)行了簡單的輸入過濾。 過濾有兩種方式,一種是在客戶端的過濾,一種是在服務(wù)器端的過濾。現(xiàn)在很多的程序員考慮到再服務(wù)器端進(jìn)行過濾可能給服務(wù)器造成更多的負(fù)荷,會把檢測過程放在客戶端。如果他在服務(wù)器端沒做任何事情,那么還是可以對其進(jìn)行攻擊的,我可以將這個登錄頁的源代碼COPY下來,然后自己建立一個文件把這些代碼PASTE進(jìn)去,再對這個文件進(jìn)行進(jìn)一步的深加工,去掉原來頁的過濾機(jī)制,或者直接將攻擊代碼寫到這個文件中去,然后將form中的action中的地址改成絕對地址,也就是將文件名改成"http://www.target.com/targer.php"這樣,然后就可 以提交啦。但是如 果服務(wù)器端加上了"來路檢測",你就白玩了。如果這樣還是不行,我再換一種方法,在瀏覽器的地址欄里用?來輸入?yún)?shù),就好像 "http://www.targer.com/targer.php?username='aa' or username<>'aa'&pass='aa' or pass<>'aa' "然后敲回車吧,其 實(shí)應(yīng)該先 嘗試這種方法因?yàn)檫@用方法更簡單,防護(hù)起來也很簡單,這種提交方式不是post 而是get ,只要服務(wù)器端程序檢測你的提交方法,就可以kill掉這 個陰謀。如果單純的只檢測了"來路",還是不太安全的,可以先正確的提交一次,在提交過程中馬上停止,就是保存這個環(huán)境,然后再構(gòu)造請求。 (我做過幾次試驗(yàn)得到的結(jié)果都不太一樣,應(yīng)該是和終止的時機(jī)有關(guān),歡迎大家來交流)。 3.一個很出色的程序員,安全意識非常高,他在服務(wù)器端做了如下檢測:檢測提交的方法;檢測提交的"來路";檢測提交內(nèi)容的長度;全面檢測提交內(nèi)容,這樣我們就很難通過上面的方法對其進(jìn)行攻擊,那到保密的資料就已經(jīng)不太可能了(如果各位還有什么好的辦法,請一定來信告訴小弟,小弟在這里先謝了)。但是我還想說的是攻擊并不代表是非要入侵進(jìn)去,拿到某些東西才叫入侵,對你的機(jī)器進(jìn)行破壞也叫入侵啊,例如提交一些錯誤的請求,腳本解釋程序就會非常規(guī)矩的給你返回錯誤信息,最淺顯的后果就是暴露物理路經(jīng),有的時候一些特殊的請求會使web服務(wù)宕掉,這些個我認(rèn)為絕對是屬于攻擊,絕對是危害,也許你認(rèn)為暴露物理路徑?jīng)]有什么,是在單獨(dú)看來沒有什么,但要是在一個有計(jì)劃的攻擊里,這個就會發(fā)揮很多作用,那時你可能還會莫名為什么他們找到了我的文件呢。也許有人認(rèn)為這個是腳本解釋程序的bug,也許有的是,但是返回錯誤信息絕對不是腳本解釋程序的錯誤,這個是每個解釋程序都要做到的,在我看來這個應(yīng)該是還是程序員的問題,程序員沒有做好對錯誤的處理。每一本教你如何編寫程序的書籍里基本都會有錯誤處理之類的章節(jié),并且每種語言基本都有錯誤處理函數(shù)和方法,只不過你沒有想到罷了。至于究竟要怎么處理那就要看你對cgi程序安全的熟悉程度了,那就要看你對這種腳本語言的特性熟悉多少了,說到底就是經(jīng)驗(yàn),唯一的辦法就是多看多寫多想多交流。 4.非常優(yōu)秀的程序員,以上那些做的都非常好(也許就是你啊,畢竟不難嘛,加上很少的代碼就可以了),怎么辦??怎么辦?!怎么辦!!在一旁偷偷的佩服吧!哈哈。