PHP程序漏洞產(chǎn)生的原因和防范方法_PHP教程
教程Tag:暫無(wú)Tag,歡迎添加,賺取U幣!
推薦:用PHP與XML聯(lián)手進(jìn)行網(wǎng)站開(kāi)發(fā)一、小序 HTML簡(jiǎn)單易學(xué)又通用,一般的PHP程序就是嵌入在HTML語(yǔ)言之中實(shí)現(xiàn)的。但是隨著WEB越來(lái)越廣泛的應(yīng)用,HTML的弱點(diǎn)也越來(lái)越明顯了。XML的出現(xiàn),彌補(bǔ)了這些不足,它提供
濫用include
1.漏洞原因:
Include是編寫(xiě)PHP網(wǎng)站中最常用的函數(shù),并且支持相對(duì)路徑。有很多PHP腳本直接把某輸入變量作為Include的參數(shù),造成任意引用腳本、絕對(duì)路徑泄露等漏洞?匆韵麓a:
... $includepage=$_GET["includepage"]; include($includepage); ... |
很明顯,我們只需要提交不同的Includepage變量就可以獲得想要的頁(yè)面。如果提交一個(gè)不存在的頁(yè)面,就可以使PHP腳本發(fā)生錯(cuò)誤而泄露實(shí)際絕對(duì)路徑(這個(gè)問(wèn)題的解決辦法在下面的文章有說(shuō)明)。
2.漏洞解決:
這個(gè)漏洞的解決很簡(jiǎn)單,就是先判斷頁(yè)面是否存在再進(jìn)行Include。或者更嚴(yán)格地,使用數(shù)組對(duì)可Include的文件作出規(guī)定?匆韵麓a:
$pagelist=array("test1.php","test2.php","test3.php"); //這里規(guī)定可進(jìn)行include的文件 if(isset($_GET["includepage"])) //判斷是否有$includepage { $includepage=$_GET["includepage"]; foreach($pagelist as $prepage) { if($includepage==$prepage) //檢查文件是否在允許列表中 { include($prepage); $checkfind=true; break; } } if($checkfind==true){ unset($checkfind); } else{ die("無(wú)效引用頁(yè)!"); } } |
這樣就可以很好地解決問(wèn)題了。
小提示:有此問(wèn)題的函數(shù)還有:require(),require_once(),include_once(),readfile()等,在編寫(xiě)的時(shí)候也要注意。
未對(duì)輸入變量進(jìn)行過(guò)濾
1.漏洞原因:
這個(gè)漏洞早在ASP中出現(xiàn)過(guò),當(dāng)時(shí)造成的注入漏洞不計(jì)其數(shù)。但由于PHP在當(dāng)時(shí)的影響力較小,所以沒(méi)有太多的人能夠注意這點(diǎn)。對(duì)于PHP來(lái)說(shuō),這個(gè)漏洞的影響性比ASP更大,因?yàn)橛斜容^多的PHP腳本使用到文本型數(shù)據(jù)庫(kù)。當(dāng)然也存在SQL語(yǔ)句的注入問(wèn)題。舉個(gè)比較經(jīng)典的例子,首先是數(shù)據(jù)庫(kù)的:
$id=$_GET["id"]; $query="SELECT * FROM my_table where id='".$id."'"; //很經(jīng)典的SQL注入漏洞 $result=mysql_query($query); |
這里很明顯我們可以用注入來(lái)獲得數(shù)據(jù)庫(kù)的其它內(nèi)容了。這里就不再詳細(xì)敘述,和ASP注入一樣的,大家可以看看以前的黑防。然后我們看文本數(shù)據(jù)庫(kù)的問(wèn)題:
$text1=$_POST["text1"]; $text2=$_POST["text2"]; $text3=$_POST["text3"]; $fd=fopen("test.php","a"); fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); fclose($fd); |
文本的漏洞可以說(shuō)是更加嚴(yán)重。倘若我們的提交的變量中插入一段很小的PHP代碼,就可以另這個(gè)文本數(shù)據(jù)庫(kù)test.php變成PHP后門(mén)。甚至插入上傳代碼,讓我們可以上傳一個(gè)完善的PHP后門(mén)。接著提升權(quán)限,服務(wù)器就是你的了。
2.漏洞解決:
這個(gè)漏洞的解決方法其實(shí)很簡(jiǎn)單,就是嚴(yán)格對(duì)全部提交的變量進(jìn)行過(guò)濾。對(duì)一些敏感的字符進(jìn)行替換。我們可以借助PHP提供的htmlspecialchars()函數(shù)來(lái)替換HTML的內(nèi)容。這里給出一段例子:
//構(gòu)造過(guò)濾函數(shù) function flt_tags($text) { $badwords=array("操你媽","fuck"); //詞匯過(guò)濾列表 $text=rtrim($text); foreach($badwords as $badword) //這里進(jìn)行詞匯的過(guò)濾 { if(stristr($text,$badword)==true){ die("錯(cuò)誤:你提交的內(nèi)容含有敏感字眼,請(qǐng)不要提交敏感內(nèi)容。"); } } $text=htmlspecialchars($text); //HTML替換 //這兩行把回車替換為 $text=str_replace("\r"," ",$text); $text=str_replace("\n","",$text); $text=str_replace("&line;","│",$text); //文本數(shù)據(jù)庫(kù)分隔符"&line;"替換為全角的"│" $text=preg_replace("/\s{ 2 }/"," ",$text); //空格替換 $text=preg_replace("/\t/"," ",$text); //還是空格替換 if(get_magic_quotes_gpc()){ $text=stripslashes($text); } //如果magic_quotes開(kāi)啟,則進(jìn)行\(zhòng)'的替換 return $text; } $text1=$_POST["text1"]; $text2=$_POST["text2"]; $text3=$_POST["text3"]; //過(guò)濾全部輸入 $text1=flt_tags($text1); $text2=flt_tags($text2); $text3=flt_tags($text3); $fd=fopen("test.php","a"); fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); fclose($fd); |
經(jīng)過(guò)一番替換和過(guò)濾后,你就可以安全地把數(shù)據(jù)寫(xiě)入文本或數(shù)據(jù)庫(kù)了。
管理員判斷不完全
1.漏洞原因:
我們用PHP寫(xiě)腳本,通常要涉及管理員的權(quán)限問(wèn)題。而一些腳本僅僅對(duì)管理員權(quán)限作出"是"判斷,而往往忽略了"否"判斷。在PHP配置文件中register_globals打開(kāi)的情況下(4.2.0以后版本默認(rèn)關(guān)閉,但有不少人為了方便而打開(kāi)它,這是極度危險(xiǎn)的行為),就會(huì)出現(xiàn)提交變量冒充管理員的情況。我們看一下的例子代碼:
$cookiesign="admincookiesign"; //判斷是否Admin的cookie變量 $adminsign=$_COOKIE["sign"]; //獲取用戶的cookie變量 if($adminsign==$cookiesign) { $admin=true; } if($admin){ echo "現(xiàn)在是管理員狀態(tài)。"; } |
看上去好像很安全的樣子,呵呵,F(xiàn)在我們假設(shè)PHP配置文件中register_globals為打開(kāi)狀態(tài)。我們提交這樣一個(gè)地址“test.php?admin=true”,結(jié)果看到了嗎?我們雖然沒(méi)有正確的Cookie,但由于register_globals為打開(kāi)狀態(tài),使得我們提交的admin變量自動(dòng)注冊(cè)為true。而且腳本缺少“否”判斷,就使得我們順利地通過(guò)admin=true取得管理員的權(quán)限了。這個(gè)問(wèn)題存在于大部分網(wǎng)站和論壇當(dāng)中。
2.漏洞解決:
解決這個(gè)問(wèn)題,我們只需要在腳本中加入對(duì)管理員的“否”判斷即可。我們?nèi)匀患僭O(shè)PHP配置文件中register_globals為打開(kāi)狀態(tài)?匆幌碌拇a:
$cookiesign="admincookiesign"; //判斷是否Admin的cookie變量 $adminsign=$_COOKIE["sign"]; //獲取用戶的cookie變量 if($adminsign==$cookiesign) { $admin=true; } else { $admin=false; } if($admin){ echo "現(xiàn)在是管理員狀態(tài)。"; } |
這樣,就算攻擊者在沒(méi)有正確Cookie的情況下提交了admin=true的變量,腳本在以后的判斷中也會(huì)把$admin設(shè)置為False。這樣就解決了部分的問(wèn)題。但由于$admin是變量,倘若在以后的其他腳本引用中出現(xiàn)了漏洞使得$admin被重新賦值就會(huì)引發(fā)新的危機(jī)。因此,我們應(yīng)該使用常量來(lái)存放管理員權(quán)限的判定。使用Define()語(yǔ)句定義一個(gè)admin常量來(lái)記錄管理員權(quán)限,在此以后若配重新賦值就會(huì)出錯(cuò),達(dá)到保護(hù)的目的。看以下代碼:
$cookiesign="admincookiesign"; //判斷是否Admin的cookie變量 $adminsign=$_COOKIE["sign"]; //獲取用戶的cookie變量 if($adminsign==$cookiesign) { define(admin,true); } else { define(admin,false); } if(admin){ echo "現(xiàn)在是管理員狀態(tài)。"; } |
值得注意的是,我們使用了Define語(yǔ)句,所以在調(diào)用Admin常量時(shí)前面不要習(xí)慣性的加變量符號(hào)$,而應(yīng)該使用Admin和!admin。
文本數(shù)據(jù)庫(kù)暴露
1.漏洞原因:
前面已經(jīng)說(shuō)過(guò),由于文本數(shù)據(jù)庫(kù)具有很大的靈活性,不需要任何外部支持。加上PHP對(duì)文件的處理能力十分強(qiáng),因此文本數(shù)據(jù)庫(kù)在PHP腳本中的應(yīng)用甚廣。甚至有幾個(gè)很好的論壇程序就是使用文本數(shù)據(jù)庫(kù)的。但有得必有失,文本數(shù)據(jù)庫(kù)的安全性也是比其他數(shù)據(jù)庫(kù)要低的。
2.漏洞解決:
文本數(shù)據(jù)庫(kù)作為一個(gè)普通的文件,它可以被下載,就像MDB一樣。所以我們要用保護(hù)MDB的辦法來(lái)保護(hù)文本數(shù)據(jù)庫(kù)。把文本數(shù)據(jù)庫(kù)的后綴名改為.PHP。并在數(shù)據(jù)庫(kù)的第一行加入。這樣文本數(shù)據(jù)庫(kù)就會(huì)作為一個(gè)PHP文件,并且在第一行退出執(zhí)行。也就是返回一個(gè)空頁(yè)面,從而達(dá)到保護(hù)文本數(shù)據(jù)庫(kù)的目的。
錯(cuò)誤路徑泄露
1.漏洞原因:
PHP遇到錯(cuò)誤時(shí),就會(huì)給出出錯(cuò)腳本的位置、行數(shù)和原因,例如:
Notice: Use of undefined constant test - assumed 'test' in D:\interpub\bigfly\test.php on line 3 |
有很多人說(shuō),這并沒(méi)有什么大不了。但泄露了實(shí)際路徑的后果是不堪設(shè)想的,對(duì)于某些入侵者,這個(gè)信息可是非常重要,而事實(shí)上現(xiàn)在有很多的服務(wù)器都存在這個(gè)問(wèn)題。
有些網(wǎng)管干脆把PHP配置文件中的display_errors設(shè)置為Off來(lái)解決,但本人認(rèn)為這個(gè)方法過(guò)于消極。有些時(shí)候,我們的確需要PHP返回錯(cuò)誤的信息以便調(diào)試。而且在出錯(cuò)時(shí)也可能需要給用戶一個(gè)交待,甚至導(dǎo)航到另一頁(yè)面。
2.漏洞解決:
PHP從4.1.0開(kāi)始提供了自定義錯(cuò)誤處理句柄的功能函數(shù)set_error_handler(),但很少數(shù)腳本編寫(xiě)者知道。在眾多的PHP論壇中,我只看見(jiàn)很少一部分對(duì)此情況進(jìn)行了處理。set_error_handler的使用方法如下:
string set_error_handler ( callback error_handler [, int error_types]) |
現(xiàn)在我們就用自定義的錯(cuò)誤處理把實(shí)際路徑過(guò)濾掉。
//admin為管理員的身份判定,true為管理員。 //自定義的錯(cuò)誤處理函數(shù)一定要有這4個(gè)輸入變量$errno,$errstr,$errfile,$errline,否則無(wú)效。 function my_error_handler($errno,$errstr,$errfile,$errline) { //如果不是管理員就過(guò)濾實(shí)際路徑 if(!admin) { $errfile=str_replace(getcwd(),"",$errfile); $errstr=str_replace(getcwd(),"",$errstr); } switch($errno) { case E_ERROR: echo "ERROR: [ID $errno] $errstr (Line: $errline of $errfile) \n"; echo "程序已經(jīng)停止運(yùn)行,請(qǐng)聯(lián)系管理員。"; //遇到Error級(jí)錯(cuò)誤時(shí)退出腳本 exit; break; case E_WARNING: echo "WARNING: [ID $errno] $errstr (Line: $errline of $errfile) \n"; break; default: //不顯示Notice級(jí)的錯(cuò)誤 break; } } //把錯(cuò)誤處理設(shè)置為my_error_handler函數(shù) set_error_handler("my_error_handler"); … |
這樣,就可以很好地解決安全和調(diào)試方便的矛盾了。而且你還可以花點(diǎn)心思,使錯(cuò)誤提示更加美觀以配合網(wǎng)站的風(fēng)格。不過(guò)注意兩點(diǎn)是:
。1)E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING是不會(huì)被這個(gè)句柄處理的,也就是會(huì)用最原始的方式顯示出來(lái)。不過(guò)出現(xiàn)這些錯(cuò)誤都是編譯或PHP內(nèi)核出錯(cuò),在通常情況下不會(huì)發(fā)生。
。2)使用set_error_handler()后,error_reporting ()將會(huì)失效。也就是所有的錯(cuò)誤(除上述的錯(cuò)誤)都會(huì)交給自定義的函數(shù)處理。
其它有關(guān)于set_error_handler()的信息,大家可以參考PHP的官方手冊(cè)。
POST漏洞
1.漏洞原因:
前面已經(jīng)說(shuō)過(guò),依靠register_globals來(lái)注冊(cè)變量是個(gè)不好的習(xí)慣。在一些留言本和論壇程序中,更要嚴(yán)格檢查獲得頁(yè)面的方式和提交的時(shí)間間隔。以防止灌水式發(fā)帖和外部提交。我們看一下以下某留言本程序的代碼:
... $text1=flt_tags($text1); $text2=flt_tags($text2); $text3=flt_tags($text3); $fd=fopen("data.php","a"); fwrite($fd,"\r\n$text1&line;$text2&line;$text3"); fclose($fd); ... |
很明顯的,如果我們提交網(wǎng)址”post.php?text1=testhaha&text2=testhaha&text3=testhaha”。數(shù)據(jù)就會(huì)被正常寫(xiě)入文件中。此程序并沒(méi)有檢測(cè)變量的來(lái)源和瀏覽器獲得頁(yè)面的方式。如果我們向這個(gè)頁(yè)面重復(fù)多次提交,就會(huì)起到洪水的作用,F(xiàn)在也有一些軟件利用這個(gè)漏洞來(lái)在論壇或留言本上發(fā)廣告,這是可恥的行為(我朋友的留言本就在1星期內(nèi)被灌了10多頁(yè),無(wú)奈)。
2.漏洞解決:
在進(jìn)行數(shù)據(jù)處理和保存前,首先判斷瀏覽器的獲得頁(yè)面方式。使用$_SERVER["REQUEST_METHOD"]變量來(lái)獲得瀏覽器的獲得頁(yè)面方式。檢查其是否為”POST”。在腳本中使用session來(lái)記錄用戶是否通過(guò)正常途徑(即填寫(xiě)提交內(nèi)容的頁(yè)面)來(lái)提交數(shù)據(jù);蚴褂$_SERVER["HTTP_REFERER"]來(lái)檢測(cè),但不推薦這樣做。因?yàn)椴糠譃g覽器沒(méi)有設(shè)置REFERER,有部分防火墻也會(huì)屏蔽REFERER。另外,我們也要對(duì)提交內(nèi)容檢查,看數(shù)據(jù)庫(kù)中是否有重復(fù)內(nèi)容。以留言本為例,使用Session進(jìn)行判定:
填寫(xiě)瀏覽內(nèi)容的頁(yè)面中,我們?cè)谧钋岸思由希?
$_SESSION["allowgbookpost"]=time(); //登記填寫(xiě)時(shí)的時(shí)間 |
在接受留言數(shù)據(jù)并保存的頁(yè)面中我們?cè)谶M(jìn)行數(shù)據(jù)處理前我們也用Session進(jìn)行以下處理:
if(strtoupper($_SERVER["REQUEST_METHOD"])!=”POST”){ die("錯(cuò)誤:請(qǐng)勿在外部提交。"); } //檢查頁(yè)面獲得方法是否為POST if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("錯(cuò)誤:請(qǐng)勿在外部提交。"); } //檢查留言填寫(xiě)時(shí)的時(shí)間 if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("錯(cuò)誤:兩次提交留言的間隔不得少于 2 分鐘。"); } //檢查留言間隔 unset($_SESSION["allowgbookpost"]); //注銷allowgbookpost變量以防止一次進(jìn)入填寫(xiě)頁(yè)面多次進(jìn)行提交 $_SESSION["gbookposttime"]=time(); //登記發(fā)送留言的時(shí)間,防止灌水或惡意攻擊 ... 數(shù)據(jù)處理及保存 ... |
經(jīng)過(guò)這樣重重審查,你的程序就安全很多了。
分享:PHP中for循環(huán)語(yǔ)句的幾種“變態(tài)”用法for語(yǔ)句可以說(shuō)是PHP(同時(shí)也是多種語(yǔ)言)的循環(huán)控制部份最基本的一個(gè)語(yǔ)句了,for語(yǔ)句的執(zhí)行規(guī)律和基礎(chǔ)用法在這里就不多說(shuō),可以參見(jiàn)PHP手冊(cè)for語(yǔ)句部分。PHP手冊(cè)中對(duì)它的語(yǔ)法定義如下:
相關(guān)PHP教程:
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問(wèn)控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語(yǔ)言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語(yǔ)言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
PHP教程Rss訂閱編程教程搜索
PHP教程推薦
- 菜鳥(niǎo)學(xué)習(xí):動(dòng)態(tài)網(wǎng)頁(yè)P(yáng)HP基礎(chǔ)學(xué)習(xí)筆記
- php中serialize序列化與json性能測(cè)試的示例分析
- 新手如何使用PHP創(chuàng)建RSS閱讀器
- 如何借助開(kāi)源技術(shù)力量實(shí)現(xiàn)Web 2.0
- PHP初學(xué)者頭疼問(wèn)題總結(jié)
- php在window iis的莫名問(wèn)題的測(cè)試方法
- 淺談PHP5 OOP編程之代理與定制異常(1)
- php匹配字符中鏈接地址程序代碼
- 深入phpMyAdmin的安裝與配置的詳細(xì)步驟
- PHP session_start()問(wèn)題解疑(詳細(xì)介紹)
- 相關(guān)鏈接:
- 教程說(shuō)明:
PHP教程-PHP程序漏洞產(chǎn)生的原因和防范方法。