为了防止SQL注入攻击,PHP自带一个功能可以对输入的字符串进行处理,可以在较底层对输入进行安全上的初步处理,也即Magic Quotes。(php.ini magic_quotes_gpc)。如果magic_quotes_gpc选项启用,那么输入的字符串中的单引号,双引号和其它一些字符前将会被自动加 上反斜杠。
但Magic Quotes并不是一个很通用的解决方案,没能屏蔽所有有潜在危险的字符,并且在许多服务器上Magic Quotes并没有被启用。所以,我们还需要使用其它多种方法来防止SQL注入。
许 多数据库本身就提供这种输入数据处理功能。例如PHP的MySQL操作函数中有addslashes()、 mysql_real_escape_string()、mysql_escape_string()等函数,可将特殊字符和可能引起数据库操作出错的字 符转义。那么这三个功能函数之间有什么却别呢?下面我们就来详细讲述下。
虽然国内很多PHP程序员仍在依靠addslashes防止SQL注入,还是建议大家加强中文防止SQL注入的检查。addslashes的问题在 于黑客 可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会 被看作是单引号,所以addslashes无法成功拦截。
当然addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string吧。
另外对于php手册中get_magic_quotes_gpc的举例:
代码如下 | 复制代码 |
if (!get_magic_quotes_gpc()) { $lastname = addslashes($_POST[‘lastname’]); } else { $lastname = $_POST[‘lastname’]; } |
最好对magic_quotes_gpc已经开放的情况下,还是对$_POST[’lastname’]进行检查一下。
再说下mysql_real_escape_string和mysql_escape_string这2个函数的区别:
mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。
总结一下:
* addslashes() 是强行加;
* mysql_real_escape_string() 会判断字符集,但是对PHP版本有要求;
* mysql_escape_string不考虑连接的当前字符集。
dz中的防止sql注入就是用addslashes这个函数,同时在dthmlspecialchars这个函数中有进行一些替换$string = preg_replace(/&((#(d{3,5}|x[a-fA-F0-9]{4}));)/, &1,这个替换解决了注入的问题,同时也解决了中文乱码的一些问题
一款比较完美的php防sql注入代码,很多初学者都有被sql注入的经验吧,今天我们来分享你一款比较完整的sql防注入代码,有需要的同学可以参考一下/代码如下 | 复制代码 |
<? /************************* 说明: 判断传递的变量中是否含有非法字符 如$_POST、$_GET 功能: 防注入 *************************/ //要过滤的非法字符 $ArrFiltrate=array("'","or","and","union","where"); //出错后要跳转的url,不填则默认前一页 $StrGoUrl=""; //是否存在数组中的值 function FunStringExist($StrFiltrate,$ArrFiltrate){ foreach ($ArrFiltrate as $key=>$value){ if (eregi($value,$StrFiltrate)){ return true; } } return false; } //合并$_POST 和 $_GET if(function_exists(array_merge)){ $ArrPostAndGet=array_merge($HTTP_POST_VARS,$HTTP_GET_VARS); }else{ foreach($HTTP_POST_VARS as $key=>$value){ $ArrPostAndGet[]=$value; } foreach($HTTP_GET_VARS as $key=>$value){ $ArrPostAndGet[]=$value; } } //验证开始 foreach($ArrPostAndGet as $key=>$value){ if (FunStringExist($value,$ArrFiltrate)){ echo "<script language='javascript'>alert('传递的信息中不得包含{',or,and,union}等非法字符请您把他们换成{‘,OR,AND,UNION}');</script>"; if (empty($StrGoUrl)){ echo "<script language='javascript'>history.go(-1);</script>"; }else{ echo "<script language='javascript'>window.location='".$StrGoUrl."';</script>"; } exit; } } /***************结束防止PHP注入*****************/ ?> |
代码如下 | 复制代码 |
|
base64_decode
将 BASE64 编码字符串解码。
语法: string base64_decode(string encoded_data);
返回值: 字符串
函数种类: 编码处理
内容说明
本函数将以 MIME BASE64 编码字符串解码。解码后的字符串可能为中文字符串或其它的二进位资料。
例
代码如下 | 复制代码 |
<?php $str = 'VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw=='; echo base64_decode($str); ?> |
str urlencode($string)
此功能是方便的编码字符串时要在URL的查询的一部分用来作为一种方便的方法传递变量到下一页。
我写了这个简单的函数,创建一个GET查询的网址()从一个数组:
代码如下 | 复制代码 |
<?php $query_string = 'foo=' . urlencode($foo) . '&bar=' . urlencode($bar); echo '<a href="mycgi?' . htmlentities($query_string) . '">'; ?> |
看一个两个综合的函数
代码如下 | 复制代码 |
<?php $encryption = "username"; echo base64_encode ($encryption);//echo "dXNlcm5hbWU= "; echo "<br>"; echo urlencode("http://".$encryption);//echo " http%3A%2F%2Fusername "; echo "<br>"; echo sha1($encryption);//echo "249ba36000029bbe97499c03db5a9001f6b734ec" echo "<br>"; ?> |
方法一:密码比对
思路:首先通过用户输入的用户名去查询数据库,得到该用户名在数据库中对应的密码,再将从数据库中查询到的密码和用户提交过来的密码进行比对。
代码:
代码如下 | 复制代码 |
$sql="select password from users where username='$name'"; $res=mysql_query($sql,$conn); if ($arr=mysql_fetch_assoc($res)){//如果用户名存在 if ($arr['password']==$pwd) {//密码比对 echo "登录成功"; }else{ echo "密码输入有误"; } }else { echo "该用户名不存在"; } |
分析:该情况下,代码健壮了不少,即使在magic_quote_gpc=Off的情况下,也能防止SQL注入攻击。因为攻击者想成功登录的话,得绕过两道坎,第一是输入的用户名要存在,这一步可以构造一个SQL语句(‘ or 1=1%23)直接绕过,但是这样子无法通过第二道坎。因为需要用户输入一个正确的密码才能通过,显然,这已经拒绝了SQL注入攻击。
方法二:使用PDO的PDO::prepare()预处理操作来防止SQL注入攻击
思路:创建一个pdo对象,利用pdo的预处理操作可以防止SQL注入攻击
代码:
代码如下 | 复制代码 |
$name=$_GET['username']; $pwd=$_GET['password']; $sql="select * from users where username=? and password=?"; //1.创建一个pdo对象 $pdo=new PDO("mysql:host=localhost;port=3306;dbname=injection","root",""); //2.设置编码 $pdo->exec("set names 'utf8'"); //3.预处理$sql语句 $pdoStatement=$pdo->prepare($sql); //4.把接收到的用户名和密码填入 $pdoStatement->execute(array($name,$pwd)); //5.取出结果 $res=$pdoStatement->fetch(); if(empty($res)){ echo "用户名或密码输入有误"; }else{ echo "登录成功"; } |