1php.ini文件中的一个设置:magic_quotes_gpc。 ○
此设置默认是关闭的,即magic_quotes_gpc=off,一般将其设置为on。为on时,php应用程序服务器将自动把用户提交的对SQL的查询进行转换,比如吧“‟”转化为“\\‟”,它的作用是在敏感字符前加一个反斜杠“\\”,这对防止SQL注入有重大作用。
2函数addslashes() ○
作用是在所有 外部数据敏感字符‟(单引号)、\\(反斜杠)、NUL的前面加上反斜杠。 3函数intval() ○
作用是将数据类型转化为整型。
注意:在新版本PHP中,即使magic_quotes_gpc设成了on,在使用addslashes()函数来处理时不会出现冲突的,可以大胆使用。
2、sql漏洞注入原理 1基础过滤和二次过滤 ○
一般情况下,在获得用户提交的参数时,首先要进行一些基础性的过滤,然后再根据程序的响应的功能以及用户输入进行二次过滤。在所有用户输入处对敏感字符进行过滤,敏感字符如下:
\"\\\\\\"?\
在javascript中使用代码过滤敏感字符串:
3、防注入的php代码: //PHP整站防注入程序,需要在公共文件中require_once本文件 //判断magic_quotes_gpc状态 if(@get_magic_quotes_gpc()){ $_GET = sec($_GET); $_POST = sec($_POST); $_COOKIE = sec($_COOKIE); $_FILES = sec($_FILES); }
$_SERVER = sec($_SERVER); function sec(&$array){ //如果是数组,遍历数组,递归调用 if(is_array($array)){ foreach ($array as $k => $v){ $array[$k] = sec($v); } }else if(is_string($array)){ //使用addslashes函数来处理 $array = addslashes($array); }else if(is_numeric($array)){ $array = intval($array); } return $array; }
//整型过滤函数
function num_check($id) { if(!$id){die('参数不能为空!');}//是否为空的判断 else if (inject_check($id)){die('非法参数');}//注入判断 else if (!is_numetic($id)){die('非法参数');}//数字判断 $id = intval($id);//整型化 return $id; }
//字符过滤函数
function str_check($str){ if(inject_check($str)){die('非法参数');}//注入判断 $str = htmlspecialchars($str);//转换html return $str; }
function search_check($str){ $str = str_replace(\"_\把\"_\"过滤掉 $str = str_replace(\"%\把\"%\"过滤掉 $str = htmlspecialchars($str);//转换html return $str; }
//表单过滤函数
function post_check($str,$min,$max){ if(isset($min) && strlen($str)< $min){ die('最少$min字节'); }else if(isset($max)&&strlen($str)>$max){ die('最多$max字节'); } return stripslashes_array($str); }
//防注入函数
function inject_check($sql_str){ return
eregi('select|inert|update|delete|\\'|\\/\\*|\\*|\\.\\.\\/|\\.\\/|UNION|into|load_file|outfile',$sql_str);//进行过滤,防注入 }
function stripslashes_array(&$array){ if(is_array($array)){ foreach ($array as $k => $v){ $array[$k] = stripslashes_array($v); } }else if(is_string($array)){ $array = stripslashes($array); } return $array; } ?>
以上程序可以在网站的一个公共文件中进行包含,它是结合实际经验写的一个通用过滤程序。
Sec函数会首先处理以GET、POST、COOKIES、SERVER、$_FILES方式传递过来的变量,对于数字类型的数据将它转化为整型,对于字符串类型进行addslashes处理,如果是数字类型则递归处理。这样做极大的提高安全性,起到防范注入漏洞的作用。
这个程序很全面,$_FILES是通过HTTP POST方式传递的已上传文件项目组成的数组,是自动全局变量。$_SERVER是一个包含诸如头部(head)、路径(path)和脚步为之(script locations)的数组,数组的实体有web服务器创建。
为了进一步提高安全性,防范注入漏洞和跨站攻击,在以后的程序中,无论是GET、POST还是COOKIE方式获得的变量,如果是整型,可以进一步使用num_check函数处理;如果是字符串类型,使用str_check函数处理。对于搜索的地方,可以使用search_check函数处理;对于发表评论表单等地方,以为难免经常出现各种符号,甚至是HTML代码,为消除sec函数的addslashes影响,最好调用上述程序中的post_check函数进行处理。Num_check、str_check、search_check等函数没有再次进行addslashes处理,因为这是不对的。如hh‟s book,addslashes处理一次会变成bookhh\\‟s,处理两次会变成bookhh\\\\‟s book。如果合理利用,上述程序将是一个比较完善的PHP防注入程序。
实际上,程序中有时候经常需要消除转义字符的影响,在magic_quotes_gpc设成了on的情况下,使用stripslashes函数来处理,此函数功能与addslashes函数完全相反。这样处理之后,程序相当于始终处于magic_quotes_gpc为off的情况下,许多程序都是这么处理的。这意味一旦出现注入漏洞,就会产生很大的危害,程序不magic_quotes_gpc的影响,得不到有效的保护。
4、防注入示例
以下是有漏洞的代码: define('ROOT', substr(dirname(__FILE__), 0, -7)); require_once('config.php');
require_once('include/func_db_mysql.php'); // 初始化数据库类
$DB = new DB_MySQL;
$DB->connect($servername, $dbusername, $dbpassword, $dbname, $usepconnect); unset($servername, $dbusername, $dbpassword, $dbname, $usepconnect); // 允许程序在register_globals = off 的环境下工作 function stripslashes_array(&$array) { if (is_array($array)) { foreach ($array as $k => $v) { $array[$k] = stripslashes_array($v); } } else if (is_string($array)) { $array = stripslashes($array); } return $array; }
@set_magic_quotes_runtime(0); // 判断magic_quotes_gpc 状态 /**/
if (@get_magic_quotes_gpc()) {
$_GET = stripslashes_array($_GET); $_POST = stripslashes_array($_POST);
$_COOKIE = stripslashes_array($_COOKIE);
}
$linkid =$_GET['id'];
$todo=(isset($_GET['do']))? $_GET['do'] : \"link\"; if ($todo == \"link\"){ //$sql=\"SELECT * FROM {$db_prefix}links WHERE linkid=$linkid\"; $sql=\"SELECT * FROM {$db_prefix}links WHERE linkid='$linkid'\"; echo $sql; $query = $DB->query($sql); print<< while ($link = $DB->fetch_array($query)){ print<< $DB->free_result($query); } ?> 以上代码无论magic_quotes_gpc为on还是off的情况下都是有漏洞的,因为里面用stripslashes_array函数进行了出来,stripslashes_array函数的目的是消除 magic_quotes_gpc的影响,因为magic_quotes_gpc的转义有时候是不希望看到的,它带来不好的影响。magic_quotes_gpc函数调用了stripslashes函数,stripslashes函数和addslashes函数是相反的。Stripslashes_array函数出来了所有GET、POST、COOKIE方式获得的变量,这样,相对于城下始终处于magic_quotes_gpc为off的情况下。 这就是漏洞产生的原因,而漏洞的形成是$linkid=$_GET[„id‟];这句话造成的,因为$linkid以GET方式获得但是没有经过任何过滤,直接放在$sql=”select * from {$db_prefix}links where linkid=$linkid”;语句中进行查询。虽然MySQL不支持多句执行,但是依然可以借助MySQL的特性进行注入,而且MySQL的UNION SELECT语法非常有用,可以实现跨表查询。因为在fy_links这张表中无论如何查询都是没有价值的信息,而UNION SELECT则可以查询fy_users表,fy_users表的信息是比较敏感的,里面有管理员的md5密码。 1将上述代码保存在sql.php文件中,放在服务器目录下,界面如下: ○ 2首先在网站后面加上单引号“‟”,看参数id是否被过滤了。这是探测的第一○ 步,如果页面正常跳转,则说明此文件没有漏洞。探测结果如下如: 3在URL后面加上and 1=1,网址如:http://localhost/fy/sql.php?id=2 and 1=1,发○ 现页面返回正常。因为程序中使用的是where linked=$linkid形式,此处也没有必要考虑闭合单引号。接着在URL后面加上and 1=2,页面返回不正常。如图: 这样比较之后,发现返回的结果是不一样,可以确定sql.php存在严重的注入漏洞,而且注入将会很顺利,这是一种很典型的漏洞。 4接下来的知道fy_links的字段数,才可以方便UNION SELECT查询。UNION○ 链接两条SQL语句,最难掌握的就是字段数,如果看过Mysql参考手册,就知道了咋select的多个表所检索的列(字段)必须具有同样的类型。第一个select查询中使用的列名将作为结果集的列名返回。简单的说,也就是UNION后面查询的字段数量、字段类型都应该和前面的select一样,而且,如果前面的select为真,就同时返回两个select的结果,当前面的select为假时,就会返回第二个select所得的结果,某些情况会替换掉在第一个select中原来应该显示的字段。 如果不知道数据类型和字段数量,可以用1来慢慢试,因为1属于int\\str\\var类型。探测的过程不断增加1的数量,当字段数量与1的个数不等时会出现下图错误: 如果相等,页面返回正常。此处fy_links表里面有6个字段,所以访问 http://localhost/fy/sql.php?id=2 union select 1,1,1,1,1,1 from fy_users where userid=1时页面返回正常。如图: 5获取fy_users表中的用户的信息 ○ 知道字段数量,现在可以进行UNION SELECT查询了,访问 http://localhost/FYblog/sql.php?id=200 union select 1,1,1,password,1,1 from fy_users where userid=1,页面显示如下图: 在上图中,已经把用户md5密码显示在页面上了,如果想获得表中用户userid=1的其他信息,可以构造查询语句,将以上网址中的password换成username可获得用户userid=1的用户名。 上面的注入方法中用到了比较多的技巧,首先id=200,200是一个不存在的id,只有这样,才会把后面的一张表的信息显示出来,否则还是显示第一张表的内容。另外,字段位置的确定,一要靠经验,二要靠尝试,上面的1可以换成0或其他。 6获得admin的md5密码,可以使用暴力破解工具破解密文,md5在线解密等; ○ 还可以下载服务器敏感文件到本地,输入网址: http://localhost/FYblog/sql.php?id=200 union select 1,1,1,1,1,load_file ('C:/wamp/www/FYblog/config.php') into outfile 'c:/user1.txt',页面返回如下图: 看到的warning不用管它。此处,C:/wamp/www/FYblog/config.php是FYblog系统的配置文件,此查询语句使用load_file命令读取它,然后导出到C:/user1.txt文件中。在真实攻击中经常导出到web目录,方便读取。那么user1.txt中的数据如下图: 注意:load_file的为放在了第六个字段位置,这里的判断需要经验,load_file()一定是字符类型的,只要放置的位置原字段也是字符类型的就可以了。 7证据如漏洞的防范 ○ 第一种方法:程序中主动过滤,修改程序中的代码,对获得的便利进行过滤。 $linkid = $_GET[„id‟]; 这一句改成下面的形式就安全了 $linkid = intval($_GET[„id‟]); 第二种方法:修改php.ini的设置,修改magic_quotes_gpc为on并去掉,具体如下所示: If(@get_magic_quotes_gpc()) { $_GET = stripslashes_array(_ET); $_POST = stripslashes_array(_OST); $_COOKIE = stripslashes_array(_OOKIE); } 以上几行代码使得magic_quotes_gpc不起作用,所以的去掉,否则修改magic_quotes_gpc为on是没有用的。实际上,这样处理还不够,应 因为$sql = “select *from {$db_prefix}links where linked = $linkid”;这里的查询不是这样的形式:$sql = “select *from {$db_prefix}links where linked = „inkid‟;第二种形式是安全的,因为加上了单引号。在第二种形式中,假设访问URL: http://localhost/FYblog/sql.php?id=200 union select 1,1,1,password,1,1 from fy_users where userid=1,那么最终的sql语句如下表示: Select *from fy_links where linked = „200 union select 1,1,username,password,loginip,1 from fy_users where userid = 1‟ 提交的一切东西都在引号当中,这样,当然就安全了。这样的sql查询不到任何结果,自然就完成不了诸如。如果没有将sql语句改成第二种形式,那么黑客可以突破magic_quotes_gpc的影响,比如语句:union select 1,1,1,1,1,load_file(„c:/boot.ini‟),可以转换为union select 1,1,1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105)),此时URL中不含有单引号了,诸如就不用考虑magic_quotes_gpc的转换,注入程序将一样的顺利。 第三种方法:不用修改php.ini设置,但是要去掉: If(@get_magic_quotes_gpc()) { $_GET = stripslashes_array(_ET); $_POST = stripslashes_array(_OST); $_COOKIE = stripslashes_array(_OOKIE); } 接着要用到以上过滤代码sec.php,在程序中,有require_once(„include/sec.php‟);这些还不够,还要进一步处理变量$linkid=$_GET[„id‟];需要改为 $inkid=num_check($_GET[„id‟])。当然第一中方法很简单的解决了问题,第三种方法适合整站过滤,更具有全局性。 因篇幅问题不能全部显示,请点此查看更多更全内容友情链接
EOT;