PHP安全模式详解(PHP5.4安全模式将消失)
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_SYSTEMsafe_mode_gid"0"PHP_INI_SYSTEM自 PHP 4.1.0 起可用safe_mode_include_dirNULLPHP_INI_SYSTEM自 PHP 4.1.0 起可用safe_mode_exec_dir""PHP_INI_SYSTEMsafe_mode_allowed_env_vars"PHP_"PHP_INI_SYSTEMsafe_mode_protected_env_vars"LD_LIBRARY_PATH"PHP_INI_SYSTEMopen_basedirNULLPHP_INI_SYSTEMdisable_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 或者[php]view plaincopyprint?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”的方法关闭,例如某些虚拟主机中:[php]view plaincopyprint?<Directory/serverroot/test>php_admin_valueopen_basedir/docroot</Directory>在 Windows 中,用分号分隔目录。在任何其它系统中用冒号分隔目录。作为 Apache 模块时,父目录中的 open_basedir 路径自动被继承。用 open_basedir 指定的限制实际上是前缀,不是目录名。也就是说“open_basedir = /dir/incl”也会允许访问“/dir/include”和“/dir/incls”,如果它们存在的话。如果要将访问限制在仅为指定的目录,用斜线结束路径名。例如:“open_basedir = /dir/incl/”。注:支持多个目录是 3.0.7 加入的。默认是允许打开所有文件。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的响应头信息里面包含了如下信 息:[php]view plaincopyprint?ServerApache/2.2.19(Win32)PHP/5.3.8fiebug查看:
3、 实战演示当safe_mode设置为 on,PHP 将通过文件函数或其目录检查当前脚本的拥有者是否和将被操作的文件的拥有者相匹配。例如:[plain]view plaincopyprint?4-rw-r--r--1httpdroot722012-04-1600:51test.php4-rw-r--r--1rootroot18532012-03-2816:20/etc/passwd运行 test.php[php]view plaincopyprint?<?phpfopen('/etc/passwd','r');readfile('/etc/passwd');mkdir('test');如果安全模式被激活,则将会导致以下错误:[php]view plaincopyprint?Warning:fopen()[function.fopen]:SAFEMODERestrictionineffect.Thescriptwhoseuidis1003isnotallowedtoaccess/etc/passwdownedbyuid0in/usr/local/httpd/htdocs/test.phponline2Warning:fopen(/etc/passwd)[function.fopen]:failedtoopenstream:Inappropriateioctlfordevicein/usr/local/httpd/htdocs/test.phponline2Warning:readfile()[function.readfile]:SAFEMODERestrictionineffect.Thescriptwhoseuidis1003isnotallowedtoaccess/etc/passwdownedbyuid0in/usr/local/httpd/htdocs/test.phponline3Warning:readfile(/etc/passwd)[function.readfile]:failedtoopenstream:Inappropriateioctlfordevicein/usr/local/httpd/htdocs/test.phponline3也可以单独地屏蔽某些函数。请注意disable_functions选项不能在php.ini文件外部使用,也就是说无法在httpd.conf文件的按不同虚拟主机或不同目录的方式来屏蔽函数。如果将如下内容加入到php.ini文件:[php]view plaincopyprint?disable_functionsreadfile,system则会得到如下的输出:[php]view plaincopyprint?Warning:readfile()hasbeendisabledforsecurityreasonsin/usr/local/httpd/htdocs/test.phponline3
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(所有者)。 (onsourceandtarget)chgrp()检查被操作的文件或目录是否与正在执行的脚本有相同的 UID(所有者)。chown()检查被操作的文件或目录是否与正在执行的脚本有相同的 UID(所有者)。chmod()检查被操作的文件或目录是否与正在执行的脚本有相同的 UID(所有者)。 另外,不能设置 SUID、SGID 和 sticky bitstouch()检查被操作的文件或目录是否与正在执行的脚本有相同的 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 起受影响)