<!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="SQL 注入" HREF="security.database.sql-injection.html"><LINK REL="NEXT" TITLE="使用 Register Globals" HREF="security.globals.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.database.sql-injection.html" ACCESSKEY="P" >上一页</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="security.globals.html" ACCESSKEY="N" >下一页</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="chapter" ><H1 ><A NAME="security.errors" >章 28. 错误报告</A ></H1 ><P > 对于 PHP 的安全性来说错误报告是一把双刃剑。一方面可以提高安全性,另一方面又有害。 </P ><P > 攻击系统时经常使用的手法就是输入不正确的数据,然后查看错误提示的类型及上下文。这样做有利于攻击者收集服务器的信息以便寻找弱点。比如说,如果一个攻击者知道了一个页面所基于的表单信息,那么他就会尝试修改变量: <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN6719" ></A ><P ><B >例 28-1. 用自定义的 HTML 页面攻击变量</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><PRE CLASS="html" ><form method="post" action="attacktarget?username=badfoo&amp;password=badfoo"> <input type="hidden" name="username" value="badfoo" /> <input type="hidden" name="password" value="badfoo" /> </form></PRE ></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 通常 PHP 所返回的错误提示都能帮助开发者调试程序,它会提出哪个文件的哪些函数或代码出错,并指出错误发生的在文件的第几行,这些就是 PHP 本身所能给出的信息。很多 PHP 开发者会使用 <A HREF="function.show-source.html" ><B CLASS="function" >show_source()</B ></A >、<A HREF="function.highlight-string.html" ><B CLASS="function" >highlight_string()</B ></A > 或者 <A HREF="function.highlight-file.html" ><B CLASS="function" >highlight_file()</B ></A > 函数来调试代码,但是在正式运行的网站中,这种做法可能会暴露出隐藏的变量、未检查的语法和其它的可能危及系统安全的信息。在运行一些具有内部调试处理的程序,或者使用通用调试技术是很危险的。如果让攻击者确定了程序是使用了哪种具体的调试技术,他们会尝试发送变量来打开调试功能: <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN6726" ></A ><P ><B >例 28-2. 利用变量打开调式功能</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><PRE CLASS="html" ><form method="post" action="attacktarget?errors=Y&amp;showerrors=1&amp;debug=1"> <input type="hidden" name="errors" value="Y" /> <input type="hidden" name="showerrors" value="1" /> <input type="hidden" name="debug" value="1" /> </form></PRE ></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 不管错误处理机制如何,可以探测系统错误的能力会给攻击者提供更多信息。 </P ><P > 比如说,PHP 的独有的错误提示风格可以说明系统在运行 PHP。如果攻击者在寻找一个 .html 为页面,想知道其后台的技术(为了寻找系统弱点),他们就会把错误的数据提交上去,然后就有可以得知系统是基于 PHP 的了。 </P ><P > 一个函数错误就可能暴露系统正在使用的数据库,或者为攻击者提供有关网页、程序或设计方面的有用信息。攻击者往往会顺藤摸瓜地找到开放的数据库端口,以及页面上某些 bug 或弱点等。比如说,攻击者可以一些不正常的数据使程序出错,来探测脚本中认证的顺序(通过错误提示的行号数字)以及脚本中其它位置可能泄露的信息。 </P ><P > 一个文件系统或者 PHP 的错误就会暴露 web 服务器具有什么权限,以及文件在服务器上的组织结构。开发者自己写的错误代码会加剧此问题,导致泄漏了原本隐藏的信息。 </P ><P > 有三个常用的办法处理这些问题。第一个是彻底地检查所有函数,并尝试弥补大多数错误。第二个是对在线系统彻底关闭错误报告。第三个是使用 PHP 自定义的错误处理函数创建自己的错误处理机制。根据不同的安全策略,三种方法可能都适用。 </P ><P > 一个能提前阻止这个问题发生的方法就是利用 <A HREF="function.error-reporting.html" ><B CLASS="function" >error_reporting()</B ></A > 来帮助使代码更安全并发现变量使用的危险之处。在发布程序之前,先打开 E_ALL 测试代码,可以帮你很快找到变量使用不当的地方。一旦准备正式发布,就应该把 <A HREF="function.error-reporting.html" ><B CLASS="function" >error_reporting()</B ></A > 的参数设为 0 来彻底关闭错误报告或者把 <TT CLASS="filename" >php.ini</TT > 中的 <TT CLASS="literal" >display_errors</TT > 设为 off 来关闭所有的错误显示以将代码隔绝于探测。当然,如果要迟一些再这样做,就不要忘记打开 ini 文件内的 <TT CLASS="literal" >log_errors</TT > 选项,并通过 <TT CLASS="literal" >error_log</TT > 指定用于记录错误信息的文件。 <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN6741" ></A ><P ><B >例 28-3. 用 E_ALL 来查找危险的变量</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">if (</font><font color="#0000BB">$username</font><font color="#007700">) { </font><font color="#FF8000">// Not initialized or checked before usage<br /> </font><font color="#0000BB">$good_login </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">;<br />}<br />if (</font><font color="#0000BB">$good_login </font><font color="#007700">== </font><font color="#0000BB">1</font><font color="#007700">) { </font><font color="#FF8000">// If above test fails, not initialized or checked before usage<br /> </font><font color="#0000BB">readfile </font><font color="#007700">(</font><font color="#DD0000">"/highly/sensitive/data/index.html"</font><font color="#007700">);<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </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.database.sql-injection.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.globals.html" ACCESSKEY="N" >下一页</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >SQL 注入</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="security.html" ACCESSKEY="U" >上一级</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >使用 Register Globals</TD ></TR ></TABLE ></DIV ></BODY ></HTML >