PHP項目安全:使用PHP的訪問限制
轉自:計算機與網絡安全
PHP可以直接訪問本地服務器路徑以及在服務器上執行腳本文件。合理地限制PHP的訪問范圍,可以有效地制止惡意用戶對服務器的攻擊。
1、文件系統限制
在PHP中可以通過配置open_basedir來限制PHP訪問文件系統的位置,將PHP執行權限限制在特定目錄下。當PHP訪問服務器的文件系統時,這個設置的位置將被檢查。當訪問的文件在目錄之外時,PHP將拒絕訪問。
開啟open_basedir可以有效地對抗文件包含、目錄遍歷等攻擊,防止攻擊者訪問非授權目錄文件。
open_basedir=/home/web/php/
; 限定PHP的訪問目錄為/home/web/php/
為此選項設置一個值,需要注意的是,如果設置的值是一個指定的目錄,則需要在目錄最后加上一個“/”,否則會被認為是目錄的前綴。
限制訪問示例如下。
echofile_get_contents('/etc/passwd');
// 讀取非授權路徑
?>
運行結果如下所示。
Warning:file_get_contents():open_basedir restriction in effect.File(/etc/passwd) is not within the allowed path(s):(/home/web/php/) in /home/web/php/index.php on line 3
如果使用函數file_get_contents()訪問系統文件路徑/etc/passwd,由于該目錄不在/home/web/php/中,因此PHP將禁止訪問并拋出異常,從而有效地防止目錄被非法訪問。
2、遠程訪問限制
圖1所示的PHP配置,當PHP的遠程訪問選項allow_url_fopen開啟時,允許PHP系統擁有從遠程檢索數據的功能,如通過PHP來訪問遠程FTP或Web,使用file_get_contents()訪問遠程數據。

圖1 PHP遠程訪問開啟
下面是示例代碼,通過傳遞統一資源定位符(Uniform Resource Locators,URL)打開遠程地址。
$url=$_GET['url'];
$result=file_get_contents($url);
echo$result;
可以通過傳遞URL參數來間接地訪問其他網站,如輸入百度的地址來執行程序。從圖2的執行結果中可以看到,file_get_contents成功地遠程獲取了百度首頁的內容。

圖2 遠程訪問開啟執行結果
很多研發人員使用這些功能,通過FTP或是HTTP來遠程獲得數據。然而,這種方法在基于PHP應用程序中會造成一個很大的漏洞。由于部分PHP研發人員缺乏安全認知,在處理用戶提交的數據時,沒有對惡意用戶所提交的數據進行過濾或轉碼,錯誤地訪問了惡意用戶提交的數據中包含的惡意鏈接,從而將該鏈接中的攻擊代碼加載到頁面中,導致產生安全漏洞。要解決此問題,需要禁用過程訪問。
allow_url_fopen=off ; 禁用PHP遠程URL訪問
allow_url_include=off ; 禁用遠程INCLUDE文件包含
把allow_url_fopen的值更改為Off將其禁用,再次執行代碼,可以看到PHP禁止了遠程訪問,出現圖3所示“用戶遠程訪問已經關閉”的提示。

圖3 遠程訪問關閉執行結果
3、開啟安全模式
PHP的安全模式是為試圖解決共享服務器(shared-server)的安全問題而設立的。開啟之后,主要會對系統操作、文件、權限設置等方法產生影響,減少被攻擊者植入webshell所帶來的某些安全問題,從而在一定程度上避免一些未知的攻擊。
可以通過在PHP配置文件中修改safe_mode的值為On來開啟PHP安全模式。
safe_mode=on ; 開啟安全模式
safe_mode_gid=off
啟動safe_mode時,會對許多PHP函數進行限制,特別是與系統相關的文件打開、命令執行等函數。所有操作文件的函數將只能操作與腳本UID相同的文件。
如果要將其放寬到GID比較,則設置safe_mode_gid=On可以考慮只比較文件的GID。
設置safe_mode以后,所有命令執行的函數將被限制只能執行php.ini里safe_mode_exec_dir指定目錄里的程序,例如使用shell_exec()、exec()等函數執行命令的方式會被禁止。如果確實需要調用其他程序,可以在php.ini中進行如下設置。
safe_mode_exec_dir = /usr/local/php/exec
在PHP配置文件中設置選項safe_mode_include_dir,然后復制可執行程序到/usr/local/php/exec目錄,這個目錄中的可執行程序不受UID/GID檢查約束,PHP腳本就可以用shell.exec()、exec()、stustem()等函數來執行這些程序。而且該目錄里的Shell腳本還可以調用其他目錄里的系統命令。
從PHP 4.2.0版本開始,safe_mode_exec_dir參數可以接受以目錄格式字符串為前綴的匹配方式。指定的限制實際上是一個前綴,而非一個目錄名稱。例如,在系統中如果定義“safe_mode_include_dir =/dir/incl”,字符串將允許訪問“/dir/include”和“/dir/inclouds等以“/dir/ind”開頭的目錄路徑。如果希望將訪問控制在一個指定的目錄中,則應在結尾加上一個斜線。
safe_mode_include_dir = /dir/incl/
當啟用安全模式時,可以通過PHP設置選項safe_mode_allowed_env_vars來設置哪些系統環境變量可以被修改,用戶只能改變在這里提供的前綴的環境變量。默認情況下,用戶只能設置以PHP_開頭的環境變量(例如PHP_FOO = BAR)。
safe_mode_allowed_env_vars = PHP
注意,safe_mode_allowed_env_vars設置項為空,PHP將使用戶可以修改任何環境變量。
safe_mode_protected_env_vars=string
PHP的safe_mode_protected_env_vars設置項,包含由一個逗號分隔的環境變量的列表,最終用戶不能用putenv()來改變這些環境變量,甚至在safe_mode_allowed_env_vars中設置了允許修改時也不能改變這些變量。
雖然PHP的安全模式不是萬能的,但還是強烈建議打開安全模式,這樣能在一定程度上避免一些未知的攻擊。不過在啟用安全模式后會有很多限制,可能對應用帶來影響,所以還需要通過調整代碼和系統配置來綜合考慮。
4、禁用危險函數
PHP配置文件中的disable_functions選項能夠在PHP中禁用指定的函數。PHP中有很多危險的內置功能函數,如果使用不當,可能造成系統崩潰。禁用函數可能會為研發帶來不便,但禁用的函數太少又可能增加研發人員寫出不安全代碼的概率,同時為攻擊者非法獲取服務器權限提供便利。
在PHP配置文件中添加需要禁用的函數可以有效地避免webshell,如下所示就是在PHP配置中添加了多個常用的禁用函數。
; http://php.net/disable-functions
disable_functions=phpinfo,eval,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket,fsockopen
表1所列是一些建議禁用的函數,要盡量避免使用這些函數,防止給系統留下隱患。

表1 建議禁用的函數