PHP 编程/配置:Register Globals
PHP 中一个常见的安全问题是 PHP 配置文件 (php.ini
) 中的 register_globals
设置。此设置(可以是 **On** 或 **Off**)指示是否将 EGPCS(环境、GET、POST、Cookie、服务器)变量的内容注册为全局变量。例如,如果 register_globals
为 **On**,则 url http://www.example.com/test.php?id=3
将声明 $id
为一个 全局变量,无需任何代码。类似地,$DOCUMENT_ROOT
也将被定义,因为它属于 $_SERVER
“超级全局” 数组。这两个例子相当于在脚本开头放置以下代码
$id = $_GET['id'];
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
此功能是一个很大的安全风险,您应该确保所有脚本的 register_globals
都为 **Off**(从 PHP 4.2.0 开始,这是默认设置,从 5.4.0 开始,该设置已完全删除)。最好通过 PHP 预定义变量来完成,例如超级全局 $_REQUEST。更安全的做法是使用:$_ENV、$_GET、$_POST、$_COOKIE 或 $_SERVER,而不是使用更通用的超级全局 $_REQUEST。
假设这段 PHP 代码位于表单的接收端。用户刚刚输入了错误的密码。$_POST 数组变量处理它。代码将描述如果密码正确(“正确密码”假设为“12345”),变量 $admin 将被设置为 TRUE。网站配置表示,如果 $admin 设置为 TRUE,该用户将拥有管理员权限。此代码与 PHP5 兼容。
if (isset($_POST['password']) && $_POST['password'] == "12345") {
$admin = TRUE;
}
register_globals 不会区分 $_POST 变量和 $_GET 变量。因此,假设用户输入了表单并将其带到了上面的页面。用户可能会认为自己应该拥有管理员权限,即使他们不知道密码。因此,该用户可以在该页面的 URL 后面附加 ?admin=1。当 register_globals 为 **On** 时,这将强制创建变量 $admin 并自动将其值设置为 1,使其等效于 TRUE。因此,register_globals 为 **On** 允许用户将变量和值**注入**到程序中!这里,无论用户是否输入了正确的密码,他们现在都可以通过对 URL 做一些操作来获得管理员权限。
如您所见,这种情况可能会在任何时候发生,只要有人足够思考以弄清楚页面的编码方式。它可能会发生在许多其他情况下。
另一个例子是会话。当 register_globals = on 时,我们也可以在下面的例子中使用 $username,但同样,您必须意识到 $username 也可以来自其他方式,比如 GET(通过 URL)。
// We wouldn't know where $username came from but do know $_SESSION is
// for session data
if (isset($_SESSION['username'])) {
echo "Hello <b>{$_SESSION['username']}</b>";
} else {
echo "Hello <b>Guest</b><br />";
echo "Would you like to login?";
}
避免它的最佳方法是确保在您的 php.ini 中将 register_globals 设置为 **Off**。但作为一个通用的编码建议,始终初始化您的变量。以下代码对之前的代码示例进行了小小的补充,但首先将 $admin 设置为 FALSE,因此用户只能通过条件语句获得管理员权限
$admin = FALSE;
if (isset($_POST["password"]) && $_POST["password"] == "12345") {
$admin = TRUE;
}
由于超级全局数组访问容易受到 代码注入[1] 的攻击,出于安全原因,最好使用 filter_input()
[2] 的语法
<?php
echo filter_input(INPUT_GET, 'password'); // good
echo $_GET['password']; // not good
?>