本节包括的所有内容均与源代码无关,但对所创建产品的安全性仍然至关重要。因为本节涉及的问题与源代码没有直接关系,所以我们将它与其他章节分开。
allow_url_fopen
选项,就可以通过 HTTP 或 FTP URL 在远程文件上执行接受文件名的 PHP 函数。该选项是在 PHP 4.0.4 中引入的,并且默认情况下是启用的,由于它可能会导致攻击者将恶意内容引入程序中,因此具有危险性。最理想的情况是,攻击者篡改了远程文件来引入到恶意内容,因此对远程文件进行操作导致应用程序容易受到攻击。最糟糕的情况是,攻击者控制了运行应用程序的 URL,这样一来,攻击者就可以将一个 URL 提供给远程服务器,从而可以将任意恶意内容注入到应用程序中。 $file
的值由一个请求参数控制,因此攻击者有可能违背程序员的假设,将一个 URL 提供给远程文件。
<?php
$file = fopen ($_GET["file"], "r");
if (!$file) {
// handle errors
}
while (!feof ($file)) {
$line = fgets ($file, 1024);
// operate on file content
}
fclose($file);
?>
allow_url_include
选项,会导致用于指定在当前页面包含某个文件的 PHP 函数,如 include()
和 require()
,接受指向远程文件的 HTTP 或 FTP URL。该选项是在 PHP 5.2.0 中引入的,并且默认情况下被禁用,由于它可能会导致攻击者将恶意内容引入程序中,因此具有危险性。最理想的情况是,攻击者篡改了远程文件来引入恶意内容,因此包含远程文件导致应用程序容易受到攻击。最糟糕的情况是,攻击者控制了应用程序用来指定要包含的远程文件的 URL,这样一来,攻击者就可以将一个 URL 提供给远程服务器,从而可以将任意恶意内容注入应用程序中。cgi.force_redirect
选项(该选项默认情况下是启用的),对 /cgi-bin/php 目录具有访问权限的攻击者就可以利用 PHP 解释器权限访问任意 Web 文档,从而绕过服务器将执行的任何 access control 检查。dl
可用于规避 open_basedir
限制。enable_dl
配置允许动态加载库。攻击者可能借此规避使用 open_basedir 配置设置的限制,而且可能允许访问系统上的任何文件。enable_dl
更便于攻击者利用其他漏洞。file_uploads
选项,可能会让 PHP 用户将任意文件上传到服务器中。允许用户上传文件这一功能本身并不代表一种安全漏洞。但是,这一功能可能会引起一系列的攻击,因为它让恶意用户能够随意向服务器环境中引入数据。
<?php
$udir = 'upload/'; // Relative path under Web root
$ufile = $udir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $ufile)) {
echo "Valid upload received\n";
} else {
echo "Invalid upload rejected\n";
} ?>
open_basedir
配置选项,该配置选项会尝试阻止 PHP 程序对 php.ini 中指定的目录树之外的文件进行操作。如果未使用 open_basedir
选项指定目录,则在 PHP 下运行的程序可以全面访问本地文件系统上的任意文件,这样攻击者将能够读取、写入或创建本不应该访问的文件。open_basedir
指定一组限制性目录,很可能为攻击者利用其他漏洞提供便利。open_basedir
选项可从整体上增强安全性,但此实现方法会面临争用情况,有些时候攻击者还可能借此绕过限制 [2]。从 PHP 执行访问权限检查到打开文件这段时间存在检查时间、使用时间 (TOCTOU) 争用情况。如同其他语言文件系统的争用情况一样,攻击者可以利用此争用情况,将通过访问控制检查的文件的符号链接替换为其他未通过检查的符号链接,从而获得对受保护文件的访问权限。safe_mode
,safe_mode_exec_dir
选项会限制 PHP 仅从指定的目录执行命令。尽管禁用 safe_mode_exec_dir
条目这一做法本身并不是一种安全漏洞,但这一画蛇添足的行为可能会被攻击者利用,并结合其他漏洞制造更大的危机。open_basedir
配置可指定可以更改的工作目录。open_basedir
配置选项将试图阻止 PHP 程序在 php.ini 中指定的目录树外的文件上运行。如果使用 .
指定工作目录,则攻击者可能会使用 chdir()
更改此目录。open_basedir
选项从总体上有利于保证系统的安全性,但它的实施效果却受到 race condition 的不利影响,这种状况可能会允许攻击者在某些情况下绕过该选项所定义的限制条件 [2]。在 PHP 执行访问权限检查与打开文件的两个时刻之间,存在一种 TOCTOU(检查时间,使用时间)race condition。与其他语言中 file system 的 race condition 一样,这种紊乱状况会导致攻击者能够将指向一个通过 access control 检查的文件的 symlink 替换为另一个本不能通过测试的文件,从而获得对受保护文件的访问权限。register_globals
选项,会导致 PHP 对 EGPCS(Environment、GET、POST、Cookie 及 Server)变量进行全局注册,这样一来,任何用户在任何 PHP 程序中都将能访问这些变量。如果程序员在编写程序时启用此选项,或多或少都会导致程序察觉不到它们所依赖于的数值来源,这会导致运行正常的环境发生意外行为,使系统容易受到恶意环境中的攻击者发起的攻击。由于认识到 register_globals
所隐含的安全隐患,在 PHP 4.2.0 中默认禁用了该选项,而在 PHP 6 中弃用并删除了该选项。$username
的值来源于由服务器控制的会话,但是攻击者可能会为 $username
提供一个恶意值来代替请求参数。如果启用 register_globals
选项,此代码会在它所生成的 HTML 内容中包含由攻击者提交的恶意值。
<?php
if (isset($username)) {
echo "Hello <b>$username</b>";
} else {
echo "Hello <b>Guest</b><br />";
echo "Would you like to login?";
}
?>
safe_mode
选项是 PHP 中最重要的 security features 之一。如果禁用 safe_mode
选项,PHP 会以调用它的用户所具有的权限对文件进行操作,而该用户通常是一个特权用户。尽管将 PHP 配置为禁用 safe_mode
,这一做法本身不会引发安全漏洞,但这一画蛇添足的行为可能会被攻击者利用,并结合其他漏洞制造更大的危机。session.use_trans_sid
,会导致 PHP 通过 URL 传递会话 ID,这样一来,攻击者就更容易劫持当前会话,或者哄骗用户使用已被攻击者控制的现有会话。 open_basedir
存在一个设计缺陷,使该选项容易发生文件访问 race condition,从而可能使攻击者绕过 file system 上的 access control 检查。open_basedir
配置选项,该选项会试图阻止 PHP 程序对 php.ini 文件中所指定的目录结构以外的文件进行操作。尽管 open_basedir
选项从总体上有利于保证安全性,但它的实施效果却受到 race condition 的不利影响,这种状况可能会允许攻击者在某些情况下绕过该选项所定义的限制条件 [2]。在 PHP 执行访问权限检查与打开文件的两个时刻之间,存在一种 TOCTOU(检查时间,使用时间)race condition。与其他语言中 file system 的 race condition 一样,这一漏洞会导致攻击者能够将指向一个通过 access control 检查的文件的 symlink 替换为另一个本不能通过测试的文件,从而获得对受保护文件的访问权限。form-bean
条目。form-bean
名称重复往往表示遗留调试代码或印刷错误。form-bean
名称重复无任何意义,因为当在多个 <form-bean>
标签中使用同一名称时,只会注册最后一个条目。form-bean
条目。
<form-beans>
<form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="name" type="java.lang.String" />
<form-property name="password" type="java.lang.String" />
</form-bean>
<form-bean name="loginForm" type="org.apache.struts.validator.DynaActionForm">
<form-property name="favoriteColor" type="java.lang.String" />
</form-bean>
</form-beans>
path
属性定位处理请求所需的资源。由于路径是指相对于模块的位置,如果不以“/”字符开头,则会导致错误。示例 2:以下配置使用的路径不以“/”字符开头。
<global-exceptions>
<exception key="global.error.invalidLogin" path="" scope="request" type="InvalidLoginException" />
</global-exceptions>
<global-forwards>
<forward name="login" path="Login.jsp" />
</global-forwards>
input
属性会导致错误。input
属性[2]。input
属性指定发生验证错误时用于显示错误消息的页面。input
属性。
<action-mappings>
<action path="/Login"
type="com.LoginAction"
name="LoginForm"
scope="request"
validate="true" />
</action-mappings>
type
属性的 <exception>
标签。<exception>
标签要求定义异常类型。缺少 type
属性或属性为空表示异常句柄多余或意外遗漏。如果开发人员有意处理异常但忘记定义异常类型,则应用程序可能会泄漏有关系统的敏感信息。<exception>
标签类型。
<global-exceptions>
<exception
key="error.key"
handler="com.mybank.ExceptionHandler"/>
</global-exceptions>
action
指向不存在的 form-bean
,则无法正确映射。form-bean
条目将 HTML 表单映射到操作。如果 <action>
标签的 name
属性与 form-bean
的名称不符,则无法映射操作,表示存在多余的定义或印刷错误。bean2
映射。
<form-beans>
<form-bean name="bean1" type="coreservlets.UserFormBean" />
</form-beans>
<action-mappings>
<action path="/actions/register1" type="coreservlets.RegisterAction1" name="bean1" scope="request" />
<action path="/actions/register2" type="coreservlets.RegisterAction2" name="bean2" scope="request" />
</action-mappings>
name
属性的 form-bean
。form-bean
名称将 HTML 表单映射到操作。如果 form-bean
无名称,则无法映射到操作,同时表示存在多余的定义或意外省略 Bean。form-bean
包含空 name
属性。
<form-beans>
<form-bean name="" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="name" type="java.lang.String" />
<form-property name="password" type="java.lang.String" />
</form-bean>
</form-beans>
form-bean
不含 type
属性,则无法正确映射。form-bean
条目将 HTML 表单映射到操作。如果 form-bean
无类型,则无法映射到操作。form-bean
包含空 type
属性。
<form-beans>
<form-bean name="loginForm" type="">
<form-property name="name" type="java.lang.String" />
<form-property name="password" type="java.lang.String" />
</form-bean>
</form-beans>