Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > by-pkgid > 05cd670d8a02b2b4a0ffb1756f2e8308 > files > 12323

php-manual-zh-5.2.4-1mdv2008.1.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>文件系统安全</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="PHP 手册"
HREF="index.html"><LINK
REL="UP"
TITLE="安全"
HREF="security.html"><LINK
REL="PREVIOUS"
TITLE="以 Apache 模块安装时"
HREF="security.apache.html"><LINK
REL="NEXT"
TITLE="数据库安全"
HREF="security.database.html"><META
HTTP-EQUIV="Content-type"
CONTENT="text/html; charset=UTF-8"></HEAD
><BODY
CLASS="chapter"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>PHP 手册</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="security.apache.html"
ACCESSKEY="P"
>上一页</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="security.database.html"
ACCESSKEY="N"
>下一页</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="chapter"
><H1
><A
NAME="security.filesystem"
>章 26. 文件系统安全</A
></H1
><P
>&#13;    PHP 遵从大多数服务器系统中关于文件和目录权限的安全机制。这就使管理员可以控制哪些文件在文件系统内是可读的。必须特别注意的是全局的可读文件,并确保每一个有权限的用户对这些文件的读取动作都是安全的。
   </P
><P
>&#13;    PHP 被设计为以用户级别来访问文件系统,所以完全有可能通过编写一段
    PHP 代码来读取系统文件如
    /etc/passwd,更改网络连接以及发送大量打印任务等等。因此必须确保
    PHP 代码读取和写入的是合适的文件。
   </P
><P
>&#13;    请看下面的代码,用户想要删除自己主目录中的一个文件。假设此情形是通过
    web 界面来管理文件系统,因此 Apache 用户有权删除用户目录下的文件。
   </P
><P
>&#13;    <TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
CLASS="EXAMPLE"
><TR
><TD
><DIV
CLASS="example"
><A
NAME="AEN6578"
></A
><P
><B
>例 26-1. 不对变量进行安全检查会导致……</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
CELLPADDING="5"
><TR
><TD
><code><font color="#000000">
<font color="#0000BB">&lt;?php<br /></font><font color="#FF8000">// 从用户目录中删除指定的文件<br /></font><font color="#0000BB">$username </font><font color="#007700">= </font><font color="#0000BB">$_POST</font><font color="#007700">[</font><font color="#DD0000">'user_submitted_name'</font><font color="#007700">];<br /></font><font color="#0000BB">$homedir </font><font color="#007700">= </font><font color="#DD0000">"/home/$username"</font><font color="#007700">;<br /></font><font color="#0000BB">$file_to_delete </font><font color="#007700">= </font><font color="#DD0000">"$userfile"</font><font color="#007700">;<br /></font><font color="#0000BB">unlink </font><font color="#007700">(</font><font color="#DD0000">"$homedir/$userfile"</font><font color="#007700">);<br />echo </font><font color="#DD0000">"$file_to_delete has been deleted!"</font><font color="#007700">;<br /></font><font color="#0000BB">?&gt;</font>
</font>
</code></TD
></TR
></TABLE
></DIV
></TD
></TR
></TABLE
>
    既然 username 变量可以通过用户表单来提交,那就可以提交别人的用户名和文件名,并删除该文件。这种情况下,就要考虑其它方式的认证。想想看如果提交的变量是“../etc/”和“passwd”会发生什么。上面的代码就等同于:
    <TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
CLASS="EXAMPLE"
><TR
><TD
><DIV
CLASS="example"
><A
NAME="AEN6581"
></A
><P
><B
>例 26-2. ……文件系统攻击</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
CELLPADDING="5"
><TR
><TD
><code><font color="#000000">
<font color="#0000BB">&lt;?php<br /></font><font color="#FF8000">// 删除硬盘中任何 PHP 有访问权限的文件。如果 PHP 有 root 权限:<br /></font><font color="#0000BB">$username </font><font color="#007700">= </font><font color="#DD0000">"../etc/"</font><font color="#007700">;<br /></font><font color="#0000BB">$homedir </font><font color="#007700">= </font><font color="#DD0000">"/home/../etc/"</font><font color="#007700">;<br /></font><font color="#0000BB">$file_to_delete </font><font color="#007700">= </font><font color="#DD0000">"passwd"</font><font color="#007700">;<br /></font><font color="#0000BB">unlink </font><font color="#007700">(</font><font color="#DD0000">"/home/../etc/passwd"</font><font color="#007700">);<br />echo </font><font color="#DD0000">"/home/../etc/passwd has been deleted!"</font><font color="#007700">;<br /></font><font color="#0000BB">?&gt;</font>
</font>
</code></TD
></TR
></TABLE
></DIV
></TD
></TR
></TABLE
>
    有两个重要措施来防止此类问题。
    <P
></P
><UL
><LI
><P
>&#13;       只给 PHP 的 web 用户很有限的权限。
      </P
></LI
><LI
><P
>&#13;       检查所有提交上来的变量。
      </P
></LI
></UL
>
    下面是改进的脚本:
    <TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
CLASS="EXAMPLE"
><TR
><TD
><DIV
CLASS="example"
><A
NAME="AEN6589"
></A
><P
><B
>例 26-3. 更安全的文件名检查</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
CELLPADDING="5"
><TR
><TD
><code><font color="#000000">
<font color="#0000BB">&lt;?php<br /></font><font color="#FF8000">// 删除硬盘中 PHP 有权访问的文件<br /></font><font color="#0000BB">$username </font><font color="#007700">= </font><font color="#0000BB">$_SERVER</font><font color="#007700">[</font><font color="#DD0000">'REMOTE_USER'</font><font color="#007700">]; </font><font color="#FF8000">// 使用认证机制<br /><br /></font><font color="#0000BB">$homedir </font><font color="#007700">= </font><font color="#DD0000">"/home/$username"</font><font color="#007700">;<br /><br /></font><font color="#0000BB">$file_to_delete </font><font color="#007700">= </font><font color="#0000BB">basename</font><font color="#007700">(</font><font color="#DD0000">"$userfile"</font><font color="#007700">); </font><font color="#FF8000">// 去除变量中的路径<br /></font><font color="#0000BB">unlink </font><font color="#007700">(</font><font color="#0000BB">$homedir</font><font color="#007700">/</font><font color="#0000BB">$file_to_delete</font><font color="#007700">);<br /><br /></font><font color="#0000BB">$fp </font><font color="#007700">= </font><font color="#0000BB">fopen</font><font color="#007700">(</font><font color="#DD0000">"/home/logging/filedelete.log"</font><font color="#007700">,</font><font color="#DD0000">"+a"</font><font color="#007700">); </font><font color="#FF8000">// 记录删除动作<br /></font><font color="#0000BB">$logstring </font><font color="#007700">= </font><font color="#DD0000">"$username $homedir $file_to_delete"</font><font color="#007700">;<br /></font><font color="#0000BB">fwrite </font><font color="#007700">(</font><font color="#0000BB">$fp</font><font color="#007700">, </font><font color="#0000BB">$logstring</font><font color="#007700">);<br /></font><font color="#0000BB">fclose</font><font color="#007700">(</font><font color="#0000BB">$fp</font><font color="#007700">);<br /><br />echo </font><font color="#DD0000">"$file_to_delete has been deleted!"</font><font color="#007700">;<br /></font><font color="#0000BB">?&gt;</font>
</font>
</code></TD
></TR
></TABLE
></DIV
></TD
></TR
></TABLE
>
    然而,这样做仍然是有缺陷的。如果认证系统允许用户建立自己的登录用户名,而用户选择用“../etc/”作为用户名,系统又一次沦陷了。所以,需要加强检查:
    <TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
CLASS="EXAMPLE"
><TR
><TD
><DIV
CLASS="example"
><A
NAME="AEN6592"
></A
><P
><B
>例 26-4. 更安全的文件名检查</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
CELLPADDING="5"
><TR
><TD
><code><font color="#000000">
<font color="#0000BB">&lt;?php<br />$username </font><font color="#007700">= </font><font color="#0000BB">$_SERVER</font><font color="#007700">[</font><font color="#DD0000">'REMOTE_USER'</font><font color="#007700">]; </font><font color="#FF8000">// 使用认证机制<br /></font><font color="#0000BB">$homedir </font><font color="#007700">= </font><font color="#DD0000">"/home/$username"</font><font color="#007700">;<br /><br />if (!</font><font color="#0000BB">ereg</font><font color="#007700">(</font><font color="#DD0000">'^[^./][^/]*$'</font><font color="#007700">, </font><font color="#0000BB">$userfile</font><font color="#007700">))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die(</font><font color="#DD0000">'bad filename'</font><font color="#007700">); </font><font color="#FF8000">// 停止执行代码<br /><br /></font><font color="#007700">if (!</font><font color="#0000BB">ereg</font><font color="#007700">(</font><font color="#DD0000">'^[^./][^/]*$'</font><font color="#007700">, </font><font color="#0000BB">$username</font><font color="#007700">))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die(</font><font color="#DD0000">'bad username'</font><font color="#007700">); </font><font color="#FF8000">// 停止执行代码<br />//后略……<br /></font><font color="#0000BB">?&gt;</font>
</font>
</code></TD
></TR
></TABLE
></DIV
></TD
></TR
></TABLE
>
   </P
><P
>&#13;    根据操作系统的不同,存在着各种各样需要注意的文件,包括联系到系统的设备(/dev/
    或者 COM1)、配置文件(/ect/ 文件和 .ini文件)、常用的存储区域(/home/ 或者 My
    Documents)等等。由于此原因,建立一个策略禁止所有权限而只开放明确允许的通常更容易些。
   </P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="security.apache.html"
ACCESSKEY="P"
>上一页</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>起始页</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="security.database.html"
ACCESSKEY="N"
>下一页</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>以 Apache 模块安装时</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="security.html"
ACCESSKEY="U"
>上一级</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>数据库安全</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>