mirror of
https://github.com/php/doc-zh.git
synced 2026-03-23 22:52:08 +01:00
203 lines
9.6 KiB
XML
203 lines
9.6 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
<!-- EN-Revision: 87d3bf2e9ea7da5abbeca3e60ea7cf7abfa6f7f3 Maintainer: lm92 Status: ready -->
|
||
<!-- CREDITS: dallas,mowangjuanzi -->
|
||
<chapter xml:id="security.cgi-bin" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>以 CGI 模式安装时</title>
|
||
|
||
<sect1 xml:id="security.cgi-bin.attacks">
|
||
<title>可能受到的攻击</title>
|
||
<simpara>
|
||
如果不想把 PHP 嵌入到服务器端软件(如 Apache)作为一个模块安装的话,可以选择以
|
||
<acronym>CGI</acronym> 的模式安装。或者把 PHP 用于不同的 <acronym>CGI</acronym>
|
||
封装以便为代码创建安全的 <command>chroot</command> 和 <command>setuid</command>
|
||
环境。这种安装方式通常会把 <command>php</command> 的可执行文件安装到 web 服务器的
|
||
<filename class="directory">cgi-bin</filename> 目录。CERT 建议书 <link
|
||
xlink:href="&url.cert;">CA-96.11</link> 建议不要把任何的解释器放到 <filename
|
||
class="directory">cgi-bin</filename> 目录。尽管 <command>php</command>
|
||
可以作为一个独立的解释器,但是它的设计使它可以防止下面类型的攻击:
|
||
</simpara>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<simpara>
|
||
访问系统文件:<filename
|
||
role="url">http://my.host/cgi-bin/php?/etc/passwd</filename>
|
||
</simpara>
|
||
<simpara>
|
||
在 URL 请求的问号(<literal>?</literal>)后面的信息会传给 CGI
|
||
接口作为命令行的参数。其它的解释器会在命令行中打开并执行第一个参数所指定的文件。
|
||
</simpara>
|
||
<simpara>
|
||
当作为 CGI 二进制文件调用时,<command>php</command> 会拒绝解释命令行参数。
|
||
</simpara>
|
||
</listitem>
|
||
<listitem>
|
||
<simpara>
|
||
访问服务器上的任意 Web 文档:<filename
|
||
role="url">http://my.host/cgi-bin/php/secret/doc.html</filename>
|
||
</simpara>
|
||
<simpara>
|
||
URL 中位于 PHP 二进制名称后面的路径信息 <filename
|
||
role="uri">/secret/doc.html</filename>,通常用于指定由 <acronym>CGI</acronym>
|
||
程序打开和解释的文件名。通常一些 web 服务器配置指令(Apache:<literal>Action</literal>)用于将 URL
|
||
(如 <filename role="url">http://my.host/secret/script.php</filename>)重定向请求到
|
||
PHP 解释器。使用此设置,Web 服务器会先检查目录 <filename role="uri">/secret</filename>
|
||
的访问权限,然后创建 <filename role="url">http://my.host/cgi-bin/php/secret/script.php</filename>
|
||
的重定向请求。不幸的是,如果请求最初是这种形式发出的,那么 Web 服务器不会对文件
|
||
<filename role="uri">/secret/script.php</filename> 进行任何访问检查,而只会对
|
||
<filename role="uri">/cgi-bin/php</filename> 进行访问检查。
|
||
这样任何能访问 <filename role="uri">/cgi-bin/php</filename> 的用户都可以访问
|
||
web 服务器上任何受保护的文档。
|
||
</simpara>
|
||
<simpara>
|
||
在 PHP 里,运行时配置指令
|
||
<link linkend="ini.cgi.force-redirect">cgi.force_redirect</link>、
|
||
<link linkend="ini.doc-root">doc_root</link> 和
|
||
<link linkend="ini.user-dir">user_dir</link>
|
||
都可以为服务器上的文件和目录添加限制,用于防止这类攻击。下面将对各个选项的设置进行详细讲解。
|
||
</simpara>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="security.cgi-bin.default">
|
||
<title>情形一:只运行公开的文件</title>
|
||
|
||
<simpara>
|
||
如果 web 服务器中所有内容都受到密码或 IP
|
||
地址的访问限制,就不需要设置这些选项。如果
|
||
web 服务器不支持重定向,或者 web 服务器不能和 PHP
|
||
通信而使访问请求变得更为安全,可以开启
|
||
<link linkend="ini.cgi.force-redirect">cgi.force_redirect</link> ini
|
||
指令。除此之外,还要确认 PHP 程序不依赖其它方式调用,比如通过直接的
|
||
<filename role="php">http://my.host/cgi-bin/php/dir/script.php</filename>
|
||
访问或通过重定向访问
|
||
<filename role="php">http://my.host/dir/script.php</filename>。
|
||
</simpara>
|
||
<simpara>
|
||
在Apache中,重定向可以使用 <literal>AddHandler</literal> 和 <literal>Action</literal> 语句来设置,请看下一节。
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="security.cgi-bin.force-redirect">
|
||
<title>情形二:使用 <literal>cgi.force_redirect</literal></title>
|
||
<simpara>
|
||
配置指令 <link linkend="ini.cgi.force-redirect">cgi.force_redirect</link>
|
||
可以防止任何人通过如
|
||
<filename role="php">http://my.host/cgi-bin/php/secretdir/script.php</filename>
|
||
这样的 URL 直接调用 <command>php</command>。PHP 在此模式下只会解析已经通过了
|
||
web 服务器的重定向规则的 URL。
|
||
</simpara>
|
||
<simpara>
|
||
通常 Apache 中的重定向设置可以通过以下指令完成:
|
||
</simpara>
|
||
<programlisting role="apache-conf">
|
||
<![CDATA[
|
||
Action php-script /cgi-bin/php
|
||
AddHandler php-script .php
|
||
]]>
|
||
</programlisting>
|
||
<simpara>
|
||
此选项只在 Apache 下进行过测试,并且要依赖于 Apache
|
||
在重定向操作中所设置的非标准 CGI 环境变量
|
||
<envar>REDIRECT_STATUS</envar>。如果 web
|
||
服务器不支持任何方式能够判断请求是直接的还是重定向的,就不能使用这个选项,而应该用其它方法。请看下一节。
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="security.cgi-bin.doc-root">
|
||
<title>情形三:设置 doc_root 或 user_dir</title>
|
||
<simpara>
|
||
在 web 服务器的主文档目录中包含动态内容如脚本和可执行程序有时被认为是一种不安全的实践。如果因为配置上的错误而未能执行脚本而作为普通
|
||
HTML 文档显示,那就可能导致知识产权或密码资料的泄露。所以很多系统管理员都会专门设置一个只能通过
|
||
PHP CGI 来访问的目录,这样该目录中的内容只会被解析而不会原样显示出来。
|
||
</simpara>
|
||
<simpara>
|
||
对于前面所说无法判断是否重定向的情况,很有必要在主文档目录之外建立一个专用于脚本的
|
||
<link linkend="ini.doc-root">doc_root</link> 目录。
|
||
</simpara>
|
||
<simpara>
|
||
可以通过<link linkend="configuration.file">配置文件</link>内的
|
||
<link linkend="ini.doc-root">doc_root</link>
|
||
指令或设置环境变量
|
||
<envar>PHP_DOCUMENT_ROOT</envar> 来定义 PHP 脚本主目录。如果设置了该项,那么
|
||
PHP 的 <acronym>CGI</acronym> 版本就只会解释 <parameter>doc_root</parameter>
|
||
目录下的文件,并确保目录外的脚本不会被 PHP
|
||
解释器执行(下面所说的 <parameter>user_dir</parameter> 除外)。
|
||
</simpara>
|
||
<simpara>
|
||
另一个可用的选项就是
|
||
<link linkend="ini.user-dir">user_dir</link>。当 <parameter>user_dir</parameter>
|
||
没有设置的时候,<parameter>doc_root</parameter>
|
||
就是唯一能控制在哪里打开文件的选项。访问如
|
||
<filename role="url">http://my.host/~user/doc.php</filename>
|
||
这个 URL 时,并不会打开用户主目录下文件,而只会执行
|
||
<parameter>doc_root</parameter> 目录下的
|
||
<filename role="uri">~user/doc.php</filename>(这个子目录以
|
||
[<literal>~</literal>] 作开头)。
|
||
</simpara>
|
||
<simpara>
|
||
如果设置了 <parameter>user_dir</parameter>,例如
|
||
<filename role="dir">public_php</filename>,那么像
|
||
<filename role="url">http://my.host/~user/doc.php</filename>
|
||
这样的请求将会执行用户主目录下的
|
||
<filename role="dir">public_php</filename> 子目录下的
|
||
<filename>doc.php</filename> 文件。假设用户主目录的绝对路径是
|
||
<filename role="dir">/home/user</filename>,那么被执行文件将会是
|
||
<filename>/home/user/public_php/doc.php</filename>。
|
||
</simpara>
|
||
<simpara>
|
||
<parameter>user_dir</parameter> 的设置与
|
||
<parameter>doc_root</parameter> 无关,所以可以分别控制
|
||
PHP 脚本的主目录和用户目录。
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="security.cgi-bin.shell">
|
||
<title>情形四:PHP 解释器放在 web 目录以外</title>
|
||
<para>
|
||
一个非常安全的做法就是把 PHP 解释器放在 web 目录外的地方,比如说
|
||
<filename role="dir">/usr/local/bin</filename>。这样做唯一不便的地方就是必须在每一个包含
|
||
PHP 代码的文件的第一行加入如下语句:
|
||
<informalexample>
|
||
<programlisting>
|
||
<![CDATA[
|
||
#!/usr/local/bin/php
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
还要将这些文件的属性改成可执行。也就是说,要像处理用
|
||
Perl 或 sh 或其它任何脚本语言写的 CGI 脚本一样,使用以 <literal>#!</literal>
|
||
开头的 shell-escape 机制来启动它们。
|
||
</para>
|
||
<para>
|
||
要使 PHP 能使用此设置正确处理
|
||
<envar>PATH_INFO</envar> 和 <envar>PATH_TRANSLATED</envar>
|
||
信息,需要开启
|
||
<link linkend="ini.cgi.discard-path">cgi.discard_path</link> ini 指令。
|
||
</para>
|
||
</sect1>
|
||
|
||
</chapter>
|
||
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|