關注安全問題的重要性
看到的遠非全部阻止用戶惡意破壞你的程式最有效卻經常被忽略的方法是在寫代碼時就考慮它的可能性。留意代碼中可能的安全問題是很重要的。考慮下邊的旨在簡化用PHP中寫入大量文本文件的過程的實例函數:
- < ?php
- function write_text($filename, $text="") {
- static $open_files = array(); // 如果文件名空,關閉全部文件
- if ($filename == NULL) {
- foreach($open_files as $fr) {
- fclose($fr);
- }
- return true;
- }
- $index = md5($filename);
- if(!isset($open_files[$index])) {
- $open_files[$index] = fopen($filename, "a+");
- if(!$open_files[$index]) return false;
- }
- fputs($open_files[$index], $text);
- return true;
- }
- ?>
這個函數帶有兩個缺省參數,文件名和要寫入文件的文本。函數將先檢查文件是否已被打開;如果是,將使用原來的文件句柄。否則,將自行創建。在這兩種情況中,文本都會被寫入文件。如果傳遞給函數的文件名是NULL,那麼所有打開的文件將被關閉,下邊提供了一個使用上的實例。如果開發者以下邊的格式來寫入多個文本文件,那麼這個函數將清楚和易讀的多。讓我們假定這個函數存在於一個單獨的文件中,這個文件包含了調用這個函數的代碼,下邊是一個這樣的程式,我們叫它quotes.php:
- < html>< body>
- < form action="< ?=$_SERVER['PHP_SELF']?>" method="get">
- Choose the nature of the quote:
- < select name="quote" size="3">
- < option value="funny">Humorous quotes< /option>
- < option value="political">Political quotes< /option>
- < option value="love">Romantic Quotes< /option>
- < /select>< br />
- The quote: < input type="text" name="quote_text" size="30" />
- < input type="submit" value="Save Quote" />
- < /form>
- < /body>< /html>
- < ?php
- include_once('write_text.php');
- $filename = "/home/web/quotes/{$_GET['quote']}";
- $quote_msg = $_GET['quote_text'];
- if (write_text($filename, $quote_msg)) {
- echo "< center>< hr>< h2>Quote saved!< /h2>< /center>";
- } else {
- echo "< center>< hr>< h2>Error writing quote< /h2>< /center>";
- }
- write_text(NULL);
- ?>
如同你看到的,這位開發者使用了write_text()函數來創建一個體系使得用戶可以提交他們喜歡的格言,這些格言將被存放在一個文本文件中。不幸的是,開發者可能沒有想到,這個程式也允許了惡意用戶危害web server的安全。也許現在你正撓著頭想著究竟這個看起來很無辜的程式怎樣引入了安全風險。當這個URL傳遞給web server 時將會發生什麼?顯然,quotes.php將被執行,但是,不是將一句格言寫入到我們希望的三個文件中之一,相反的,一個叫做different_file.dat的新文件將被建立,其中包含一個字符串garbage data。
顯然,這不是我們希望的行為,惡意用戶可能通過把quote指定為../../../etc/passwd來訪問UNIX密碼文件從而創建一個帳號盡管這需要web server以superuser運行程式,如果是這樣的,你應該停止閱讀,馬上去修復它)。如果/home/web/quotes/可以通過浏覽器訪問,可能這個程式最嚴重的安全問題是它允許任何用戶寫入和運行任意PHP程式。這將帶來無窮的麻煩。
這裡有一些解決方案。如果你只需要寫入目錄下的一些文件,可以考慮使用一個相關的數組來存放文件名。如果用戶輸入的文件存在於這個數組中,就可以安全的寫入。另一個想法是去掉所有的不是數字和字母的字符來確保沒有目錄分割符號。還有一個辦法是檢查文件的擴展名來保證文件不會被web server執行。原則很簡單,作為一個開發者你必須比程式在你希望的情況下運行時考慮更多。如果非法數據進入到一個form元素中會發生什麼?惡意用戶是否能使你的程式以不希望的方式運行?什麼方法能阻止這些攻擊?你的web server和PHP程式只有在最弱的安全鏈接下才安全,所以確認這些可能不安全的鏈接是否安全很重要。
常見的涉及安全的錯誤
這裡給出一些要點,一個可能危及安全的編碼上的和管理上的失誤的簡要不完整列表:
◆錯誤1:信賴數據
這是貫穿於我關於PHP程式安全的討論的主題,你決不能相信一個來自外部的數據。不管它來自用戶提交表單,文件系統的文件或者環境變量,任何數據都不能簡單的想當然的采用。所以用戶輸入必須進行驗證並將之格式化以保證安全。
◆錯誤2:在web目錄中存儲敏感數據
任何和所有的敏感數據都應該存放在獨立於需要使用數據的程式的文件中,並保存在一個不能通過浏覽器訪問的目錄下。當需要使用敏感數據時,再通過include 或 require語句來包含到適當的PHP程式中。
◆錯誤3:不使用推薦的安全防范措施
PHP手冊包含了在使用和編寫PHP程式時關於安全防范的完整章節。手冊也幾乎)基於案例清楚的說明了什麼時候存在潛在安全風險和怎麼將風險降低到最低。又如,惡意用戶依靠開發者和管理員的失誤得到關心的安全信息以獲取系統的權限。留意這些警告並適當的采取措施來減小惡意用戶給你的系統帶來真正的破壞的可能性。