1. 安全模式
一直沒有用過php的safe_mode安全模式,以此說明作為日后參考。
PHP 的安全模式是為了試圖解決共享服務器(shared-server)安全問題而設立的。在結構上,試圖在 PHP 層上解決這個問題是不合理的,但修改 web 服務器層和操作系統層顯得非常不現實。因此許多人,特別是 ISP,目前使用安全模式。
safe_mode是唯一PHP_INI_SYSTEM屬性,必須通過php.ini或httpd.conf來設置。要啟用safe_mode,只需修改php.ini: safe_mode = On 或者修改httpd.conf,定義目錄:Options FollowSymLinks php_admin_value safe_mode 1,重啟apache后safe_mode就生效了。
啟動safe_mode,會對許多PHP函數進行限制,特別是和系統相關的文件打開、命令執行等函數。 所有操作文件的函數將只能操作與腳本UID相同的文件。(腳本的uid并不一定是運行wen服務器用戶的uid)
雖然safe_mode不是萬能的(低版本的PHP可以繞過),但還是強烈建議打 開安全模式,在一定程度上能夠避免一些未知的攻擊。不過啟用 safe_mode會有很多限制,可能對應用帶來影響,所以還需要調整代碼和配置才能和諧。
安全模式配置指令:
名稱 | 默認值 | 可修改范圍 | 更新記錄 |
---|---|---|---|
safe_mode | "0" | PHP_INI_SYSTEM | |
safe_mode_gid | "0" | PHP_INI_SYSTEM | 自 PHP 4.1.0 起可用 |
safe_mode_include_dir | NULL | PHP_INI_SYSTEM | 自 PHP 4.1.0 起可用 |
safe_mode_exec_dir | "" | PHP_INI_SYSTEM | |
safe_mode_allowed_env_vars | "PHP_" | PHP_INI_SYSTEM | |
safe_mode_protected_env_vars | "LD_LIBRARY_PATH" | PHP_INI_SYSTEM | |
open_basedir | NULL | PHP_INI_SYSTEM | |
disable_functions | "" | 僅 php.ini | 自 PHP 4.0.1 起可用 |
disable_classes | "" | 僅 php.ini | 自 PHP 4.3.2 起可用 |
2. 配置選項的簡要解釋
-
safe_modeboolean
-
是否啟用 PHP 的安全模式。php的安全模式是個非常重要的內嵌的安全機制,能夠控制一些php中的函數,比如system(),
同時把很多文件操作函數進行了權限控制,也不允許對某些關鍵文件的文件,比如/etc/passwd,
但是默認的php.ini是沒有打開安全模式的,我們把它打開:
safe_mode = on 或者 -
ini_set("safe_mode",true);
safe_mode_gidboolean
-
默認情況下,安全模式在打開文件時會做 UID 比較檢查。如果想將其放寬到 GID 比較,則打開 safe_mode_gid。是否在文件訪問時使用UID(FALSE)或者GID(TRUE)來做檢查。
safe_mode_include_dirstring
-
當從此目錄及其子目錄(目錄必須在 include_path 中或者用完整路徑來包含)包含文件時越過UID/GID 檢查。
從 PHP 4.2.0 開始,本指令可以接受和 include_path 指令類似的風格用冒號(Windows 中是分號)隔開的路徑,而不只是一個目錄。
指定的限制實際上是一個前綴,而非一個目錄名。這也就是說“safe_mode_include_dir = /dir/incl”將允許訪問“/dir/include”和“/dir/incls”,如果它們存在的話。如果希望將訪問控制在一個指定的目錄,那么請在結尾加上一個斜線,例如:“safe_mode_include_dir = /dir/incl/”。
如果本指令的值為空,在 PHP 4.2.3 中以及 PHP 4.3.3 起具有不同 UID/GID 的文件將不能被包含。在較早版本中,所有文件都能被包含。
safe_mode_exec_dirstring
-
如果 PHP 使用了安全模式,system() 和其它程序執行函數將拒絕啟動不在此目錄中的程序。必須使用/ 作為目錄分隔符,包括 Windows 中。
safe_mode_allowed_env_varsstring
-
設置某些環境變量可能是潛在的安全缺口。本指令包含有一個逗號分隔的前綴列表。在安全模式下,用戶只能改變那些名字具有在這里提供的前綴的環境變量。默認情況下,用戶只能設置以 PHP_ 開頭的環境變量(例如 PHP_FOO = BAR)。
注: 如果本指令為空,PHP 將使用戶可以修改任何環境變量!
safe_mode_protected_env_varsstring
-
本指令包含有一個逗號分隔的環境變量的列表,最終用戶不能用 putenv() 來改變這些環境變量。甚至在 safe_mode_allowed_env_vars 中設置了允許修改時也不能改變這些變量。
open_basedirstring
-
將 PHP 所能打開的文件限制在指定的目錄樹,包括文件本身。本指令不受安全模式打開或者關閉的影響。
當一個腳本試圖用例如 fopen() 或者gzopen() 打開一個文件時,該文件的位置將被檢查。當文件在指定的目錄樹之外時 PHP 將拒絕打開它。所有的符號連接都會被解析,所以不可能通過符號連接來避開此限制。
特殊值 . 指明腳本的工作目錄將被作為基準目錄。但這有些危險,因為腳本的工作目錄可以輕易被chdir() 而改變。
在 httpd.conf 文件中中,open_basedir 可以像其它任何配置選項一樣用“php_admin_value open_basedir none”的方法關閉,例如某些虛擬主機中:
在 Windows 中,用分號分隔目錄。在任何其它系統中用冒號分隔目錄。作為 Apache 模塊時,父目錄中的 open_basedir 路徑自動被繼承。
用 open_basedir 指定的限制實際上是前綴,不是目錄名。也就是說“open_basedir = /dir/incl”也會允許訪問“/dir/include”和“/dir/incls”,如果它們存在的話。如果要將訪問限制在僅為指定的目錄,用斜線結束路徑名。例如:“open_basedir = /dir/incl/”。
注: 支持多個目錄是 3.0.7 加入的。
默認是允許打開所有文件。
-
<Directory /serverroot/test> php_admin_value open_basedir /docroot </Directory>
-
disable_functionsstring
-
本指令允許你基于安全原因禁止某些函數。接受逗號分隔的函數名列表作為參數。 disable_functions 不受安全模式的影響。
本指令只能設置在 php.ini 中。例如不能將其設置在httpd.conf。
-
disable_classesstring
-
本指令可以使你出于安全的理由禁用某些類。用逗號分隔類名。disable_classes 不受安全模式的影響。
本指令只能設置在php.ini 中。例如不能將其設置在httpd.conf。
-
本指令只能設置在 php.ini 中。例如不能將其設置在 httpd.conf。
-
expose_php = On/Offstring
利用整個設置,你能夠阻礙一些來自自動腳本針對web服務器的攻擊。通常情況下,http的響應頭信息里面包含了如下信 息:
-
fiebug查看:
-
-
3. 實戰演示
當 safe_mode 設置為 on,PHP 將通過文件函數或其目錄檢查當前腳本的擁有者是否和將被操作的文件的擁有者相匹配。例如:
-
-
4 -rw-r--r-- 1 httpd root 72 2012-04-16 00:51 test.php 4 -rw-r--r-- 1 root root 1853 2012-03-28 16:20 /etc/passwd
運行 test.php
<?php fopen('/etc/passwd','r'); readfile('/etc/passwd'); mkdir('test');
如果安全模式被激活,則將會導致以下錯誤:
Warning: fopen() [function.fopen]: SAFE MODE Restriction in effect. The script whose uid is 1003 is not allowed to access /etc/passwd owned by uid 0 in /usr/local/httpd/htdocs/test.php on line 2 Warning: fopen(/etc/passwd) [function.fopen]: failed to open stream: Inappropriate ioctl for device in /usr/local/httpd/htdocs/test.php on line 2 Warning: readfile() [function.readfile]: SAFE MODE Restriction in effect. The script whose uid is 1003 is not allowed to access /etc/passwd owned by uid 0 in /usr/local/httpd/htdocs/test.php on line 3 Warning: readfile(/etc/passwd) [function.readfile]: failed to open stream: Inappropriate ioctl for device in /usr/local/httpd/htdocs/test.php on line 3
也可以單獨地屏蔽某些函數。請注意disable_functions 選項不能在php.ini 文件外部使用,也就是說無法在httpd.conf 文件的按不同虛擬主機或不同目錄的方式來屏蔽函數。如果將如下內容加入到php.ini 文件:
disable_functions readfile,system
則會得到如下的輸出:
Warning: readfile() has been disabled for security reasons in /usr/local/httpd/htdocs/test.php on line 3
4. 安全模式限制函數
函數名 | 限制 |
---|---|
dbmopen() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
dbase_open() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
filepro() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
filepro_rowcount() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
filepro_retrieve() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
ifx_* | sql_safe_mode 限制, (!= safe mode) |
ingres_* | sql_safe_mode 限制, (!= safe mode) |
mysql_* | sql_safe_mode 限制, (!= safe mode) |
pg_loimport() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
posix_mkfifo() | 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
putenv() | 遵循 ini 設置的 safe_mode_protected_env_vars 和 safe_mode_allowed_env_vars 選項。請參考 putenv() 函數的有關文檔。 |
move_uploaded_file() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
chdir() | 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
dl() | 本函數在安全模式下被禁用。 |
backtick operator | 本函數在安全模式下被禁用。 |
shell_exec()(在功能上和 backticks 函數相同) | 本函數在安全模式下被禁用。 |
exec() | 只能在 safe_mode_exec_dir 設置的目錄下進行執行操作?;谀承┰?,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用于此函數的參數上。 |
system() | 只能在 safe_mode_exec_dir 設置的目錄下進行執行操作?;谀承┰?,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用于此函數的參數上。 |
passthru() | 只能在 safe_mode_exec_dir 設置的目錄下進行執行操作?;谀承┰?,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用于此函數的參數上。 |
popen() | 只能在 safe_mode_exec_dir 設置的目錄下進行執行操作?;谀承┰?,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用于此函數的參數上。 |
fopen() | 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
mkdir() | 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
rmdir() | 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
rename() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
unlink() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
copy() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 (on source and target ) |
chgrp() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
chown() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
chmod() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 另外,不能設置 SUID、SGID 和 sticky bits |
touch() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 |
symlink() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 (注意:僅測試 target) |
link() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 (注意:僅測試 target) |
apache_request_headers() | 在安全模式下,以“authorization”(區分大小寫)開頭的標頭將不會被返回。 |
header() | 在安全模式下,如果設置了 WWW-Authenticate,當前腳本的 uid 將被添加到該標頭的 realm 部分。 |
PHP_AUTH 變量 | 在安全模式下,變量 PHP_AUTH_USER 、PHP_AUTH_PW 和 PHP_AUTH_TYPE 在 $_SERVER 中不可用。但無論如何,您仍然可以使用 REMOTE_USER 來獲取用戶名稱(USER)。(注意:僅 PHP 4.3.0 以后有效) |
highlight_file(), show_source() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本后有效) |
parse_ini_file() | 檢查被操作的文件或目錄是否與正在執行的腳本有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的腳本有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本后有效) |
set_time_limit() | 在安全模式下不起作用。 |
max_execution_time | 在安全模式下不起作用。 |
mail() | 在安全模式下,第五個參數被屏蔽。(注意,僅自 PHP 4.2.3 起受影響) |
轉自:http://blog.csdn.net/hguisu/article/details/7465976
原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2975