PHP 遵從大多數伺服器系統中關於檔案和目錄權限的安全機制。這就使管理員可以控制哪些檔案在檔案系統內是可讀的。必須特別注意的是全局的可讀檔案,並確保每一個有權限的會員對這些檔案的讀取動作都是安全的。
PHP 被設計為以會員層級來訪問檔案系統,所以完全有可能通過編寫一段
PHP 代碼來讀取系統檔案如
/etc/passwd,變更網路連線以及傳送大量列印任務等等。因此必須確保
PHP 代碼讀取和寫入的是合適的檔案。
請看下面的代碼,會員想要移除自己主目錄中的一個檔案。假設此情形是通過
web 介面來管理檔案系統,因此 Apache 會員有權移除會員目錄下的檔案。
例子 26-1. 不對變量進行安全檢查會導致……
<?php // 從會員目錄中移除特殊的檔案 $username = $_POST['user_submitted_name']; $homedir = "/home/$username"; $file_to_delete = "$userfile"; unlink ("$homedir/$userfile"); echo "$file_to_delete has been deleted!"; ?>
|
|
既然 username 變量可以通過會員表單來送出,那就可以送出別人的會員名和檔案名,並移除該檔案。這種情況下,就要考慮其它模式的認證。想想看若果送出的變量是「../etc/」和「passwd」會發生什麼。上面的代碼就等同於:
例子 26-2. ……檔案系統攻擊
<?php // 移除硬碟中任何 PHP 有訪問權限的檔案。若果 PHP 有 root 權限: $username = "../etc/"; $homedir = "/home/../etc/"; $file_to_delete = "passwd"; unlink ("/home/../etc/passwd"); echo "/home/../etc/passwd has been deleted!"; ?>
|
|
有兩個重要措施來防止此類問題。
只給 PHP 的 web 會員很有限的權限。
檢查所有送出上來的變量。
下面是改進的腳本:
例子 26-3. 更安全的檔案名檢查
<?php // 移除硬碟中 PHP 有權訪問的檔案 $username = $_SERVER['REMOTE_USER']; // 使用認證機制
$homedir = "/home/$username";
$file_to_delete = basename("$userfile"); // 去除變量中的路徑 unlink ($homedir/$file_to_delete);
$fp = fopen("/home/logging/filedelete.log","+a"); // 記錄移除動作 $logstring = "$username $homedir $file_to_delete"; fwrite ($fp, $logstring); fclose($fp);
echo "$file_to_delete has been deleted!"; ?>
|
|
然而,這樣做仍然是有缺陷的。若果認證系統容許會員建立自己的登入會員名,而會員選取用「../etc/」作為會員名,系統又一次淪陷了。所以,需要加強檢查:
例子 26-4. 更安全的檔案名檢查
<?php $username = $_SERVER['REMOTE_USER']; // 使用認證機制 $homedir = "/home/$username";
if (!ereg('^[^./][^/]*$', $userfile)) die('bad filename'); // 停止執行代碼
if (!ereg('^[^./][^/]*$', $username)) die('bad username'); // 停止執行代碼 //後略…… ?>
|
|
根據動作系統的不同,存在著各種各樣需要注意的檔案,內含聯繫到系統的裝置(/dev/
或是 COM1)、配置檔(/ect/ 檔案和 .ini檔案)、常用的存儲區功能變數(/home/ 或是 My
Documents)等等。由於此原因,建立一個策略禁止所有權限而只開放明確容許的通常更容易些。