• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 安全模式

    PHP 的安全模式是为了试图解决共享服务器(shared-server)安全问题而设立的。在结构上,试图在 PHP 层上解决这个问题是不合理的,但修改 web 服务器层和操作系统层显得非常不现实。因此许多人,特别是 ISP,目前使用安全模式。

    Warning
    本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。

    保安措施和安全模式

    保安措施和安全模式配置指令
    名字默认可修改范围更新日志
    safe_mode"0"PHP_INI_SYSTEM
    safe_mode_gid"0"PHP_INI_SYSTEM自 PHP 4.1.0 起可用,在 PHP 5.4.0 中移除。
    safe_mode_include_dirNULLPHP_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
    有关 PHP_INI_* 样式的更多详情与定义,见 配置可被设定范围。

    这是配置指令的简短说明。

    $safe_modeboolean

    是否启用 PHP 的安全模式。

    $safe_mode_gidboolean

    默认情况下,安全模式在打开文件时会做 UID 比较检查。如果想将其放宽到 GID 比较,则打开 safe_mode_gid。是否在文件访问时使用UIDFALSE)或者GIDTRUE)来做检查。

    $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)。

    Note:

    如果本指令为空,PHP 将使用户可以修改任何环境变量!

    $safe_mode_protected_env_varsstring

    本指令包含有一个逗号分隔的环境变量的列表,最终用户不能用 putenv() 来改变这些环境变量。甚至在 safe_mode_allowed_env_vars 中设置了允许修改时也不能改变这些变量。

    参见 open_basedir、 disable_functions、 disable_classes、 register_globals、 display_errors 和 log_errors。

    当 safe_mode 设置为 on,PHP 将通过文件函数或其目录检查当前脚本的拥有者是否和将被操作的文件的拥有者相匹配。例如:

    -rw-rw-r--    1 rasmus   rasmus       33 Jul  1 19:20 script.php
    -rw-r--r--    1 root     root       1116 May 26 18:01 /etc/passwd
    运行script.php
    <?php
     readfile('/etc/passwd');
    ?>
    
    如果安全模式被激活,则将会导致以下错误:
    Warning: SAFE MODE Restriction in effect. The script whose uid is 500 is not
    allowed to access /etc/passwd owned by uid 0 in /docroot/script.php on line 2
    

    同时,或许会存在这样的环境,在该环境下,宽松的GID检查已经足够,但严格的UID检查反而是不适合的。可以用 safe_mode_gid 选项来控制这种检查。如果设置为On则进行宽松的GID检查;设置为Off(默认值)则进行UID检查。

    除了 safe_mode 以外,如果设置了 open_basedir 选项,则所有的文件操作将被限制在指定的目录下。例如:

    <Directory /docroot>
      php_admin_value open_basedir /docroot
    </Directory>
    如果在设置了 open_basedir 选项后运行同样的script.php,则其结果会是:
    Warning: open_basedir restriction in effect. File is in wrong directory in
    /docroot/script.php on line 2
    

    也可以单独地屏蔽某些函数。请注意 disable_functions 选项不能在php.ini文件外部使用,也就是说无法在httpd.conf文件的按不同虚拟主机或不同目录的方式来屏蔽函数。如果将如下内容加入到php.ini文件:

    disable_functions readfile,system
    则会得到如下的输出:
    Warning: readfile() has been disabled for security reasons in
    /docroot/script.php on line 2
    

    Warning

    当然,这些 PHP 限制不适用于可执行文件。

    Theres a failure with open_basedir and per-host configuration
    in apache as described in bug #42836: http://bugs.php.net/bug.php?id=42836
    I got the same errors on my development windows system and apache 2.2.4 with php 5.3.beta1.
    This error (or similar) is shown:
    Warning: Unknown: open_basedir restriction in effect. File(...)
    is not within the allowed path(s): ( \5 \5@5\5\x08,\5)
    Fix:
     - try slashes at the end of the folder name
     or
     - put "php_admin_value open_basedir ..." at first of all in the configuration
    bad/missing config values for the Plesk server running the whole thing. I just followed the directions here: https://vb.3dlat.com/
    You can configure PHP to have a separate error log file for each VirtualHost definition. The trick is knowing exactly how to set it up, because you can’t touch the configuration directly without breaking Plesk. Every domain name on your (dv) has its own directory in /var/www/vhosts. A typical directory has the following top level directories:
    cgi-bin/
    conf/
    error_docs/
    httpdocs/
    httpsdocs/
    ...and so on
    You’ll want to create a vhost.conf file in the domain directory’s conf/ folder with the following lines:
    php_value error_log /path/to/error_log
    php_flag display_errors off
    php_value error_reporting 6143
    php_flag log_errors on
    Change the first value to match your actual installation (I used /tmp/phperrors.log). After you’re done editing the vhost.conf file, test the configuration from the console with:
    apachectl configtest
    …or if you don’t have apachectl (as Plesk 8.6 doesn’t seem to)…
    /etc/init.d/httpd configtest
    And finally tell Plesk that you’ve made this change.
    /usr/local/psa/admin/bin/websrvmng -a
    Whether to enable PHP's safe mode. If PHP is compiled with --enable-safe-mode then defaults to On, otherwise Off. http://www.wikibanat.com

    保安措施和安全模式

    保安措施和安全模式配置指令
    名字默认可修改范围更新日志
    safe_mode"0"PHP_INI_SYSTEM
    safe_mode_gid"0"PHP_INI_SYSTEM自 PHP 4.1.0 起可用,在 PHP 5.4.0 中移除。
    safe_mode_include_dirNULLPHP_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
    有关 PHP_INI_* 样式的更多详情与定义,见 配置可被设定范围。

    这是配置指令的简短说明。

    $safe_modeboolean

    是否启用 PHP 的安全模式。

    $safe_mode_gidboolean

    默认情况下,安全模式在打开文件时会做 UID 比较检查。如果想将其放宽到 GID 比较,则打开 safe_mode_gid。是否在文件访问时使用UIDFALSE)或者GIDTRUE)来做检查。

    $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)。

    Note:

    如果本指令为空,PHP 将使用户可以修改任何环境变量!

    $safe_mode_protected_env_varsstring

    本指令包含有一个逗号分隔的环境变量的列表,最终用户不能用 putenv() 来改变这些环境变量。甚至在 safe_mode_allowed_env_vars 中设置了允许修改时也不能改变这些变量。

    参见 open_basedir、 disable_functions、 disable_classes、 register_globals、 display_errors 和 log_errors。

    当 safe_mode 设置为 on,PHP 将通过文件函数或其目录检查当前脚本的拥有者是否和将被操作的文件的拥有者相匹配。例如:

    -rw-rw-r--    1 rasmus   rasmus       33 Jul  1 19:20 script.php
    -rw-r--r--    1 root     root       1116 May 26 18:01 /etc/passwd
    运行script.php
    <?php
     readfile('/etc/passwd');
    ?>
    
    如果安全模式被激活,则将会导致以下错误:
    Warning: SAFE MODE Restriction in effect. The script whose uid is 500 is not
    allowed to access /etc/passwd owned by uid 0 in /docroot/script.php on line 2
    

    同时,或许会存在这样的环境,在该环境下,宽松的GID检查已经足够,但严格的UID检查反而是不适合的。可以用 safe_mode_gid 选项来控制这种检查。如果设置为On则进行宽松的GID检查;设置为Off(默认值)则进行UID检查。

    除了 safe_mode 以外,如果设置了 open_basedir 选项,则所有的文件操作将被限制在指定的目录下。例如:

    <Directory /docroot>
      php_admin_value open_basedir /docroot
    </Directory>
    如果在设置了 open_basedir 选项后运行同样的script.php,则其结果会是:
    Warning: open_basedir restriction in effect. File is in wrong directory in
    /docroot/script.php on line 2
    

    也可以单独地屏蔽某些函数。请注意 disable_functions 选项不能在php.ini文件外部使用,也就是说无法在httpd.conf文件的按不同虚拟主机或不同目录的方式来屏蔽函数。如果将如下内容加入到php.ini文件:

    disable_functions readfile,system
    则会得到如下的输出:
    Warning: readfile() has been disabled for security reasons in
    /docroot/script.php on line 2
    

    Warning

    当然,这些 PHP 限制不适用于可执行文件。

    Theres a failure with open_basedir and per-host configuration
    in apache as described in bug #42836: http://bugs.php.net/bug.php?id=42836
    I got the same errors on my development windows system and apache 2.2.4 with php 5.3.beta1.
    This error (or similar) is shown:
    Warning: Unknown: open_basedir restriction in effect. File(...)
    is not within the allowed path(s): ( \5 \5@5\5\x08,\5)
    Fix:
     - try slashes at the end of the folder name
     or
     - put "php_admin_value open_basedir ..." at first of all in the configuration
    bad/missing config values for the Plesk server running the whole thing. I just followed the directions here: https://vb.3dlat.com/
    You can configure PHP to have a separate error log file for each VirtualHost definition. The trick is knowing exactly how to set it up, because you can’t touch the configuration directly without breaking Plesk. Every domain name on your (dv) has its own directory in /var/www/vhosts. A typical directory has the following top level directories:
    cgi-bin/
    conf/
    error_docs/
    httpdocs/
    httpsdocs/
    ...and so on
    You’ll want to create a vhost.conf file in the domain directory’s conf/ folder with the following lines:
    php_value error_log /path/to/error_log
    php_flag display_errors off
    php_value error_reporting 6143
    php_flag log_errors on
    Change the first value to match your actual installation (I used /tmp/phperrors.log). After you’re done editing the vhost.conf file, test the configuration from the console with:
    apachectl configtest
    …or if you don’t have apachectl (as Plesk 8.6 doesn’t seem to)…
    /etc/init.d/httpd configtest
    And finally tell Plesk that you’ve made this change.
    /usr/local/psa/admin/bin/websrvmng -a
    Whether to enable PHP's safe mode. If PHP is compiled with --enable-safe-mode then defaults to On, otherwise Off. http://www.wikibanat.com

    被安全模式限制或屏蔽的函数

    以下安全模式列表可能不完整或不正确。

    安全模式限制函数
    函数名限制
    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()当 PHP 运行在 安全模式 时,不能使用此函数。
    backtick operator当 PHP 运行在 安全模式 时,不能使用此函数。
    shell_exec()(在功能上和 backticks 函数相同)当 PHP 运行在 安全模式 时,不能使用此函数。
    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$sourceand$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_USERPHP_AUTH_PWPHP_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 起受影响)
    session_start() The owner of a script must be the same as owner of a session.save_path directory if the defaultfilessession.save_handler is used.
    All filesystem and stream functions. 检查被操作的文件或目录是否与被执行的脚本有相同的 UID(所有者)。 检查被操作的目录是否与被执行的脚本有相同的 UID(所有者)。 (see the safe_mode_include_dirphp.inioption.
    It seems that glob and file_exists functions are also restricted in safe-mode.
    refers to the previuos posting of
    bananarama
    15-May-2006 10:11 
    "all file-handling and -management functions are restricted, just in case someones wondering why they're not listed here.
    a script can run these functions on files without errors, if the files were created (are owned) by the same UID, the script was created (is owned) by."
    .... or if the directory, in which the file is located, has the same UID as the script, which tries to use a file in that directory...