MySQL-php 对于mysql注入有什么通用的防范方法
现在我在写代码中总结的只有2种,
一是对于整数形,插入前用intval强制转换
二是对于字符串,这里是用real_escape_string再结合set_charset,主要是有些字符串会包含汉字
欢迎补充,欢迎补充此类检测工具。诸如时间戳这种影响效率的就不考虑了,而且检验起来也更复杂。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
使用pdo的prepare 可以避免这个问题,prepare实际上是提前编译sql, excute的时候才去加载用户的变量,这时候整个语句已经不是sql语句,不会有注入问题,详细猛击>>http://blog.csdn.net/lintianyi38/article/details/8076393
对于PHP程序可以通过用户提交的关键字来判断注入行为
众所周知,大概分为$_POST,$_GET,$_COOKIE三种,我们可以根据这三种简单定义规则。这里简单总结了如下规则:
$getfilter="'|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;
$postfilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;
$cookiefilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?Select|Update.+?SET|Insert\s+INTO.+?VALUES|(Select|Delete).+?FROM|(Create|Alter|Drop|TRUNCATE)\s+(TABLE|DATABASE)" ;
1.使用mysql_escape_string函数处理每一个提交给SQL的字符串。该函数是mysql扩展自身提供的,即使处理多字节字符集也应该没有BUG。
2.使用Mysql的预处理功能执行SQL,避免直接把字符串写入SQL语句。PDO对预处理的支持很好,而mysql或mysqli对预处理的支持我就不得而知了。我只用过PDO的预处理(我自己封装了一个PDO操作类,使预处理的调用变得很方便)。
PDO常规的预处理调用方式:
$db=new pdo(……);
$rs=$db->prepare('SELECT * FROM a WHERE b=? AND c=? LIMIT ?,20');
$rs->execute(array(10086,"什么'都'可以rn不用担心注入",0));
var_dump($rs->fetch());
之前收集的一个代码段,忘记出处了,一直在用,很好用,分享下。
/**
@param string $val--过滤的参数
@param string $type--过滤类型int|string|html
@param string $method--post|get|request
@return mixed
**/
function filter_val($val,$type='int',$method='post'){
$arr = array();
switch (strtoupper($method)) {
case 'POST':
$arr = $_POST;
break;
case 'GET':
$arr = $_GET;
break;
case 'REQUEST':
$arr = $_REQUEST;
break;
default:
break;
}
if (isset($arr["$val"])) {
if ($type == 'int') {
return intval($arr["$val"])?intval($arr["$val"]):0;
} elseif ($type == 'string') {
return empty($arr["$val"])?false:mysql_escape_string(strip_tags($arr["$val"]));
} elseif ($type == 'html') {
return empty($arr["$val"])?false:addslashes(strip_tags($arr["$val"],"<a><p><font><b>"));
}
} else {
return false;
}
}
直接PDO_MYSQL就可以解决注入了
/*
*本函数会进行去除不安全html字进行符和防sql止注入处理
*$string 数组或者字符串,如果是数组 则穷举数组,返回跟原来数组一样结构的过滤后的数组.
*html 如果为真,则会保留安全的html标记,否则全部html删除.
*/
$magic=get_magic_quotes_gpc();
function safe_html($string,$is_html=0){
if(is_array($string)){
foreach($string as $k=>$v){
$return[$k] = safe_html($v);
}
}else{
if(!$is_html){
$return = strip_tags($string);
}else{
$return = uh($string);
}
if(!$GLOBALS['magic']){
//var_dump($GLOBALS['magic']);
$return = mysql_real_escape_string($return);
}
$return = trim($return);
}
return $return;
}
/*本函数会去除不安全的html代码.*/
function uh($str)
{
$farr = array(
"/s+/", //过滤多余的空白
"/<(/?)(s*)(script|i?frame|input|button|style|html|body|title|link|meta|object|form|?|%)(s*)([^>]*?)>/isU",
"/(<[^>]*)on[a-zA-Z]+s*=[^>]*(>)/isU" ,//去除各种on事件
"/(href|src|background|url|dynsrc|expression|codebase) ?[=:(]( ?"?'?[javascript:|vbscript:][^>]*?)()?)([ >/])/si"//删除各种脚本标记
);
$tarr = array(
" ", //连续的空白换成单一空格
"", //如果要直接清除不安全的标签,这里可以留空
"\1\2",
""
);
$str = preg_replace( $farr,$tarr,$str);
return $str;
}
//用法:
$post = safe_html($_POST);
$get = safe_html($_GET);
$ip = safe_html($HTTP_SERVER_VARS['REMOTE_ADDR']);
通用的方法的确没什么好说的,但是我感觉除了过滤常见的恶意词语和特殊字符外,比较好的防范方法是进行来路检测,保证这个请求是从你的站点上过来的,这样能够减少攻击面,挫败不少的自动化注入工具。
function inject_check($sql_str) { //防止注入
$check = preg_match("!select|insert|update|delete|'|/*|*|../|./|union|into|load_file|outfile!i", $sql_str);
if ($check) {
echo "输入非法注入内容!";
exit ();
} else {
return $sql_str;
}
}
function checkurl() { //检查来路
if (preg_replace("/https?://([^:/]+).*/i", "1", $_SERVER['HTTP_REFERER']) !== preg_replace("/([^:]+).*/", "1", $_SERVER['HTTP_HOST'])) {
header("location: http://");
exit();
}
}
首先是对服务器的安全设置
这里主要是php+mysql的安全设置和linux主机的安全设置
对php+mysql注射的防范,首先将magic_quotes_gpc设置为On
display_errors设置为Off
我们利用intval()将其转换成整数类型,如代码:
$id=intval($id);
mysql_query=”select *from example where articieid=’$id’”;或者这样写:mysql_query(”SELECT * FROM article WHERE articleid=”.intval($id).”")
如果是字符型就用addslashes()过滤一下,然后再过滤”%”和”_”如:
$search=addslashes($search);
$search=str_replace(“_”,”_”,$search);
$search=str_replace(“%”,”%”,$search);
当然也可以加php通用防注入代码:
/*************************
PHP通用防注入安全代码
说明:
判断传递的变量中是否含有非法字符
如$_POST、$_GET
功能:
防注入
**************************/
//要过滤的非法字符
$ArrFiltrate=array(”‘”,”;”,”union”);
//出错后要跳转的url,不填则默认前一页
$StrGoUrl=”";
//是否存在数组中的值
function FunStringExist($StrFiltrate,$ArrFiltrate){
foreach ($ArrFiltrate as $key=>$value){
if (eregi($value,$StrFiltrate)){
return true;
}
}
return false;
}
mysql防注入,一般就是对页面提交(post或get)过来的数据进行处理,这里接收两种:
一是php逻辑模块,对页面提交过来的特殊字符进行转义
可以用get_magic_quotes_gpc()检测系统是否开启自动转义设置。如果没有打开这项设置,可以使用addslashes()函数添加,它的功能就是给数据库查询语句等的需要在某些字符前加上了反斜线,比如:
if (!get_magic_quotes_gpc())
{
foreach ($_POST as $_key => $_value)
{
if (!is_array($_value)) $_POST[$_key] = addslashes($_value);
}
}
二是mysql处理模块,用mysql的mysql_real_escape_string()的函数,可将特殊字符和可能引起数据库操作出错的字符转义。
if(get_magic_quotes_gpc()) {
$str=stripslashes($str);
}else{
$str = mysql_real_escape_string($str);
}