PHP 安全 (1) 原作:John Coggeshall 07/31/2003 原文:http://www.onlamp.com/pub/a/php/2003/07/31/php_foundations.html 在最近的兩篇專欄文章(《常見樣式錯誤(上)》和《常見樣式錯誤(下)》)中我討論了一些在編寫PHP程式時常見的使程式難於閱讀和易導致BUG的壞習慣。 在今天的文章中,我將轉向討論這個系列的重點:使用PHP時,安全問題的重要性。 關注安全問題的重要性 看到的遠非全部 阻止使用者惡意破壞你的程式最有效卻經常被忽略的方法是在寫代碼時就考慮它的可能性。留意代碼中可能的安全問題是很重要的。考慮下邊的旨在簡化用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,記住這個程式叫做quotes.php: http://www.somewhere.com/fun/quotes.php?quote=different_file.dat"e_text=garbage+data 當這個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程式時關於安全防範的完整章節。手冊也(幾乎)基於案例清楚的說明了什麼時候存在潛在安全風險和怎麼將風險降低到最低。又如,惡意使用者依靠開發人員和管理員的失誤得到關心的安全資訊以擷取系統的許可權。留意這些警告並適當的採取措施來減小惡意使用者給你的系統帶來真正的破壞的可能性。 |