快捷搜索:   nginx

确保PHP应用程序的安全(二)(2)

GET 变量 pid 是安全的。这会怎么样呢?大多数用户没那么聪明,无法构造出语义攻击。但是,如果他们注意到浏览器的 URL 位置域中的 pid=33,就可能开始捣乱。如果他们输入另一个数字,那么可能没问题;但是如果输入别的东西,比如输入 SQL 命令某个文件的名称(比如 /etc/passwd),或者搞别的恶作剧,比如输入长达 3,000 个字符的数值,那么会发生什么呢?

在这种情况下,要记住基本规则,不要信任用户输入。应用程序开发人员知道 template.php 接受的个人标识符(PID)应该是数字,所以可以使用 PHP 的 is_numeric() 函数确保不接受非数字的 PID,如下所示:


清单 9. 使用 is_numeric() 来限制 GET 变量
                    
<?php

$pid = $_GET['pid'];

if (is_numeric($pid)){

//we create an object of a fictional class Page
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
//......
//......
}else{
//didn't pass the is_numeric() test, do something else!
}?>

这个方法似乎是有效的,但是以下这些输入都能够轻松地通过 is_numeric() 的检查:

  • 100 (有效)
  • 100.1 (不应该有小数位)
  • +0123.45e6 (科学计数法 —— 不好)
  • 0xff33669f (十六进制 —— 危险!危险!

那么,有安全意识的 PHP 开发人员应该怎么做呢?多年的经验表明,最好的做法是使用正则表达式来确保整个 GET 变量由数字组成,如下所示:


清单 10. 使用正则表达式限制 GET 变量
                    
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg("^[0-9]+$",$pid)){
//do something appropriate, like maybe logging
//them out or sending them back to home page
}
}else{
//empty $pid, so send them back to the home page
}
//we create an object of a fictional class Page, which is now
//moderately protected from evil user input
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
//......
//......
?>

需要做的只是使用 strlen() 检查变量的长度是否非零;如果是,就使用一个全数字正则表达式来确保数据元素是有效的。如果 PID 包含字母、斜线、点号或任何与十六进制相似的内容,那么这个例程捕获它并将页面从用户活动中屏蔽。如果看一下 Page 类幕后的情况,就会看到有安全意识的 PHP 开发人员已经对用户输入 $pid 进行了转义,从而保护了 fetchPage() 方法,如下所示:


清单 11. 对 fetchPage() 方法进行转义
                    
<?php
class Page{
function fetchPage($pid){
$sql = "select pid,title,desc,kw,content,
status from page where pid='
".mysql_real_escape_string($pid)."'";
//etc, etc....

}

}
?>

您可能会问,“既然已经确保 PID 是数字,那么为什么还要进行转义?” 因为不知道在多少不同的上下文和情况中会使用 fetchPage() 方法。必须在调用这个方法的所有地方进行保护,而方法中的转义体现了纵深防御的意义。

如果用户尝试输入非常长的数值,比如长达 1000 个字符,试图发起缓冲区溢出攻击,那么会发生什么呢?下一节更详细地讨论这个问题,但是目前可以添加另一个检查,确保输入的 PID 具有正确的长度。您知道数据库的 pid 字段的最大长度是 5 位,所以可以添加下面的检查。


清单 12. 使用正则表达式和长度检查来限制 GET 变量
                    
<?php
$pid = $_GET['pid'];

if (strlen($pid)){
if (!ereg("^[0-9]+$",$pid) && strlen($pid) > 5){
//do something appropriate, like maybe logging
//them out or sending them back to home page
}
}else{
//empty $pid, so send them back to the home page
}
//we create an object of a fictional class Page, which is now
//even more protected from evil user input
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
//......
//......
?>

现在,任何人都无法在数据库应用程序中塞进一个 5,000 位的数值 —— 至少在涉及 GET 字符串的地方不会有这种情况。想像一下黑客在试图突破您的应用程序而遭到挫折时咬牙切齿的样子吧!而且因为关闭了错误报告,黑客更难进行侦察


顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论