MySQL二次漏洞处理

一、提出问题 

众所周知,数据库操作中对于一些特殊字符(例如单引号“'”、反斜线“\”等元字符)有着严格的限制,如果向数据库中写入的数据含有这样的特殊字符,操作将会带来不安全因素。所以对于用户输入的数据,我们完全认为它是没有安全性的,需要在程序中对其进行适当的过滤处理后,方可写入数据库。 

对于这点,相信大多数PHP程序员都会注意到,一般采取的方法是使用AddSlashes()字符串函数对用户输入的数据进行处理,把数据中的特殊字符加上反斜线进行转译。这样对于一般的数据库写入是正常的,并不会带来什么问题,而问题来源于之后的取出操作。对于前面用AddSlashes()函数进行转译后保存在数据库中的数据,经过查看数据库我们发现里面存储的是原始的数据,也就是说其中的特殊字符并没有被加上反斜线。此时当数据来源于这时的数据库本身时,安全问题仍然存在,这就造成了二次漏洞。 


流程描述 原始的数据,如“'”=> 程序处理(安全的数据如“\'” )=> MySQL里存 

储(原始的数据如“'”) => 程序处理(处理的是“'”)=> 产生危险 

 

二、分析问题 

因此在进行数据过滤的时候,不要只是暂时地让数据失去危害,可以考虑永久地让数据失去危害,譬如在过滤的时候不是将“'”变成“\'”等,而是在条件允许的情况下将其直接转换成HTML字符“'”,这样并不影响显示但是数据却不再会包含让数据库的元字符,所以不用担心注入漏洞了,其他的字符可以一样考虑处理。 

 

三、解决问题 

    为解决此问题,我们可以用str_replace()函数依次对必要的特殊字符进行替换。此时要注意替换后的字符串长度将会改变,每替换一个字符,字符串长度将会增加5。我们还需在写入数据库之前判断它是否超过字段大小。 

 

五、演示代码 
file:test.php 

代码: 
<?php 

/* 
*   二次漏洞简单检测 
*   Author Linvo 
*   Build 2007-11-8 
*/ 

/* 
*   链接数据库(根据情况自己修改) 
*/ 
$Host = 'localhost'; 
$User = 'root'; 
$Pass = 'password'; 
$DB = 'test'; //测试库名 
$db = @mysql_connect($Host,$User,$Pass); 

if(!$db)    die("连接服务器MySQL出错!"); 
else    if(!mysql_select_db($DB,$db))   die("连接数据库出错!"); 

define(INPUT_MAX_LENGTH, 10);   //前台maxlength值(初步检测) 
define(INDB_MAX_LENGTH, 20);    //数据库中字段设置的大小值(用于写入前的必要安全测试) 

/* 
*   原始数据(如用户输入等) 
*/ 
$string = "’\\"; //用户输入内容 

if(strlen($string) > INPUT_MAX_LENGTH) //初步检测 
    die("输入内容超长"); 

echo "输入的内容:".$string; 

/* 
*   过滤方案 
*/ 
//$string_in1 = AddSlashes($string); //方案一:临时失去危险,但有二次漏洞 
$string_in1 = str_slashes($string); //方案二:永久性失去危险!(自定义函数) 


/* 
*   安全测试 
*/ 
$string_in2 = test_db($string_in1, 1); //一次漏洞检测 
$string_in3 = test_db($string_in2, 2); //二次漏洞检测 

/* 
*   数据库操作(函数) 
*/ 
function test_db($str_in, $time) 

    echo "第 $time 次要写入的内容:".$str_in; 

    if(strlen($str_in) > INDB_MAX_LENGTH) die("第 $time 次写入数据超长!");//必要安全测试! 
    $result = mysql_query("Insert INTO str(str) VALUES('$str_in')"); //写入 

    if(!$result) 
    { 
        die("<font color=red>第 $time 次写入数据库失败</font>"); 
    } 

    echo "第 $time 次写入完毕"; 
    $result = mysql_query("Select str FROM str orDER BY id DESC LIMIT 1");//取出 
    if($item = mysql_fetch_array($result)) 
    { 
        $str_out = $item['str']; 
    } 
    echo "第 $time 次输出:".$str_out.""; 
    return $str_out; 


/* 
*   永久性过滤危险字符 
*/ 
function str_slashes($str) 

    $str = str_replace("'","'",$str); //转译 ' 
    $str = str_replace("\\","\",$str); //转译 \ 
    return $str; 


?>  




文章来自: 网络
引用通告地址: http://www.cn-sohu.com/bolg/trackback.asp?tbID=206
Tags:
评论: 0 | 引用: 121 | 查看次数: 378
发表评论
你没有权限发表留言!
分享到: