文件系統(tǒng)安全

目錄

PHP 受大多數(shù)服務(wù)器系統(tǒng)中文件和目錄權(quán)限的內(nèi)置安全機(jī)制的影響。 這允許控制文件系統(tǒng)中哪些文件是可讀的。應(yīng)該小心對待任何全局可讀的文件, 要確保所有有權(quán)限訪問該文件系統(tǒng)的用戶都可以安全的讀取文件。

PHP 被設(shè)計(jì)為以用戶級別訪問文件系統(tǒng), 因此完全可以編寫 PHP 腳本來讀取系統(tǒng)文件,例如 /etc/passwd, 修改網(wǎng)絡(luò)連接,發(fā)送大量打印任務(wù)等。這有一些明顯的影響,因此需要確保讀寫的是合適的文件。

請看下面的腳本,用戶表示想要刪除自己主目錄下的一個(gè)文件。 假設(shè) PHP web 界面通常用于文件管理, 因此 Apache 用戶允許刪除用戶主目錄中的文件。

示例 #1 不對變量檢查會導(dǎo)致....

<?php
// 從用戶主目錄移除一個(gè)文件
$username $_POST['user_submitted_name'];
$userfile $_POST['user_submitted_filename'];
$homedir  "/home/$username";

unlink("$homedir/$userfile");

echo 
"The file has been deleted!";
?>
由于 username 和 filename 由用戶表單中提交,那就能提交屬于其他人的 username 和 filename,甚至可以刪除不被允許的文件。這種情況下, 應(yīng)該使用一些其它形式的身份驗(yàn)證。不妨考慮一下,如果提交的變量是 “../etc/” 和 “passwd” 會發(fā)生什么。上面代碼將等同于:

示例 #2 ... 文件系統(tǒng)攻擊

<?php
// 刪除磁盤中任何 PHP 有訪問權(quán)限的文件。如果 PHP 有 root 權(quán)限:
$username $_POST['user_submitted_name']; // "../etc"
$userfile $_POST['user_submitted_filename']; // "passwd"
$homedir  "/home/$username"// "/home/../etc"

unlink("$homedir/$userfile"); // "/home/../etc/passwd"

echo "The file has been deleted!";
?>
有兩個(gè)重要措施來防止此類問題。
  • PHP web 用戶二進(jìn)制文件僅允許有限的權(quán)限。
  • 檢查所有提交上來的變量。
這是改進(jìn)的腳本:

示例 #3 更安全的文件名檢查

<?php
// 刪除磁盤中 PHP 有權(quán)訪問的文件。
$username $_SERVER['REMOTE_USER']; // 使用認(rèn)證機(jī)制
$userfile basename($_POST['user_submitted_filename']);
$homedir  "/home/$username";

$filepath "$homedir/$userfile";

if (
file_exists($filepath) && unlink($filepath)) {
    
$logstring "Deleted $filepath\n";
} else {
    
$logstring "Failed to delete $filepath\n";
}
$fp fopen("/home/logging/filedelete.log""a");
fwrite($fp$logstring);
fclose($fp);

echo 
htmlentities($logstringENT_QUOTES);

?>
然而,這樣做也是有缺陷的。如果認(rèn)證系統(tǒng)允許用戶創(chuàng)建自己的登錄用戶名, 而用戶選擇 “../etc/” 作為登錄名,系統(tǒng)將再次暴露。 出于這個(gè)原因,需要編寫自定義檢查:

示例 #4 更安全的文件名檢查

<?php
$username     
$_SERVER['REMOTE_USER']; // 使用認(rèn)證機(jī)制
$userfile     $_POST['user_submitted_filename'];
$homedir      "/home/$username";

$filepath     "$homedir/$userfile";

if (!
ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD'$userfile)) {
    die(
"Bad username/filename");
}

//等等...
?>

根據(jù)操作系統(tǒng)的不同,需要關(guān)心各種各樣的文件,比如設(shè)備條目(/dev/ 或 COM1)、配置文件(/etc/ 文件和 .ini 文件)、 眾所周知的文件存儲區(qū)域(/home/, My Documents)等等。出于這個(gè)原因,創(chuàng)建一個(gè)禁止所有權(quán)限而只開放明確允許的策略通常更容易些。