PHP安全-源碼暴露(二)
你的WEB服務器必須要能夠讀取你的源確并執行它,這就意味著任意人所寫的代碼被服務器運行時,它同樣可以讀取你的源碼。在一個共享主機上,最大的風險是由于WEB服務器是共享的,因此其它開發者所寫的PHP代碼可以讀取任意文件。
<?php
header(’Content-Type: text/plain’);
readfile($_GET[’file’]);
?>
通過在你的源碼所在的主機上運行上面腳本,攻擊者可以通過把file的值指定為完整的路徑和文件名來使WEB服務器讀取并顯示任何文件。例如,假定該腳本命名為file.php,位于主機example.org上,只要通過訪問下面鏈接即可使文件/path/to/source.php的內容暴露:
http://example.org/file.php?file=/path/to/source.php
當然,要使這段簡單的代碼起作用,攻擊者必須確切地知道你的源碼的位置,但是攻擊者可以寫出更復雜的腳本,通過它可以方便在瀏覽整個文件系統。關于此類腳本,請看本章后面部分的示例。
對該問題沒有完美的解決方案。正如第五章所述,你必須考慮所有你的源碼都是公開的,甚至是保存在WEB主目錄之外的代碼也是如此。
最好的辦法是把所有敏感數據保存在數據庫中。雖然這使一些代碼的編寫多了一層復雜性,但這是防止你的敏感數據暴露的最好方法。很不幸的是,還有一個問題。如何保存你的數據庫訪問密碼?
請看保存在網站主目錄之外一個名為db.inc的文件:
<?php
$db_user = ’myuser’;
$db_pass = ’mypass’;
$db_host = ’localhost’;
$db = mysql_connect($db_host, $db_user, $db_pass);
?>
如果該文件的路徑是已知的(或被猜中),就存在著你的服務器上的另外一個用戶訪問該文件的可能,就會獲取數據庫訪問權限,這樣你保存在數據庫中的所有數據就會暴露。
解決該問題的最好方案是把你的數據庫訪問權限以下面的格式保存在一個只有系統管理員權限才能讀取的文件中:
SetEnv DB_USER 'myuser'
SetEnv DB_PASS 'mypass'
SetEnv是一個Apache的指令,上面文件的意思是建立兩個分別代表你的數據庫用戶名及密碼的Apache環境變量。當然,該技巧的關鍵是只有系統管理員才能讀取該文件。如果你無法登錄成為系統管理員,你就可以限制該文件只能由你自已進行讀取,這樣的保護方式與上面的方式類似。
$ chmod 600 db.conf
$ ls db.conf
-rw------- 1 chris chris 48 May 21 12:34 db.conf
這就有效地防止了惡意腳本訪問你的數據中權限,因此對于數據庫中保存的敏感數據來說,不會有危及安全的重大風險。
為使該文件生效,你就需要能夠通過PHP訪問其中的數據。要達到這個目的,需要在httpd.conf中寫上如下的包含句:
Include '/path/to/db.conf'
需要注意該語句需要插入在VirtualHost區域內,否則其它用戶就能取得相應的內容。
由于Apache的父進程以系統管理員身份運行(需要綁定在80端口),它能夠讀取該配置文件,但處理服務器請求的子進程(運行PHP腳本)不能讀取該文件。
你可以通過$_SERVER超級全局數組去訪問這兩個變量,這樣在db.inc中,只要通過引用$_SERVER變量即可,而不是在其中寫明數據庫的權限:
<?php
$db_user = $_SERVER[’DB_USER’];
$db_pass = $_SERVER[’DB_PASS’];
$db_host = ’localhost’;
$db = mysql_connect($db_host, $db_user, $db_pass);
?>
如果該文件被暴露,數據庫訪問權也不會泄露。這對于共享主機是一大安全性改進,同時對于獨立主機也是一種深度防范手段。
注意在使用上述技巧時,數據庫訪問權限就位于$_SERVER超級公用數組中。這就需要同時限制普通訪問者運行phpinfo()察看或其它任何導致$_SERVER內容暴露的原因。
當然,你可以使用本技巧保護任何信息(不只是數據庫訪問權限),但我發現把大多數數據保存在數據庫更為方便,特別是由于該技巧需要得到你的主機提供商的協助。
相關文章: