由一次SQL注入去理解防SQL注入

来源:互联网 发布:淘宝代练可靠吗 编辑:程序博客网 时间:2024/06/01 14:06
SQL注入是PHP运用最常见的漏洞之一,很多开发人员都会时刻提防着它,防SQL注入的普遍做法是对数据输入进行过滤,以及对发送到数据库的数据进行转义。其实就是永远不要相信用户输入数据。为了更好的理解SQL注入,笔者今天自己尝试用SQL“攻击”自己了一次。以下是建立攻击的一个过程。

1、建立用户表
这里写图片描述
我用PHPMyAdmin在我test数据库建立了一张user表,表中有三个字段,分别是用户名、密码、邮箱,然后插入了一条测试数据
这里写图片描述
用户名是:周运金,密码是test(用了MD5加密)
2、建立登陆页面form.html

<html><head><title>Sql注入</title><meta http-equiv="content-type"content="text/html;charset=utf-8"></head><body><form action="validate.php" method="post">  <fieldset >    <legend>Sql注入</legend>    <table>      <tr>        <td>用户名:</td>        <td><input type="text" name="username"></td>      </tr>      <tr>        <td>密  码:</td>        <td><input type="text" name="password"></td>      </tr>      <tr>        <td><input type="submit" value="提交"></td>        <td><input type="reset" value="重置"></td>      </tr>    </table>  </fieldset></form></body></html>

效果:
这里写图片描述
3、创建处理登陆Validate.php

<?php      //面向对象的连接方式     $mysqli =new mysqli("localhost","root","123","test");      if(!$mysqli ){               echo mysqli_connect_error();           }     $mysqli->set_charset("utf8");                    $mysqli->query("set names 'utf8'");      $name=$_POST['username'];      $pwd=md5($_POST['password']);      $sql="select * from user where username='$name' and password='$pwd'";      $query=$mysqli->query($sql);      if($query == false){            echo $mysqli->error;      }      else{            $rows =$query->num_rows;            if($rows){                   header("Location:manage.php");             }else{                   echo "您的用户名或密码输入有误,<a href='form.html'>请重新登录!</a>";             }      }     $mysqli->close();?>

这里说明一下,原始MySQL在PHP5.5之后已经被php抛弃,采用面像对象连接的MYSQLI。
4、建立登陆成功的页面manage.php

<?php echo "You are a manager"; ?>

这样就完成了一个有SQL注入漏洞的登陆程序了。很明显程序没有对用户输入的数据进行处理就直接放进sql语句里面了。这是很危险的做法。
接下来就开始攻击一下吧,做法其实很简单只要去拼凑sql语句就好了。
我先输入正确的用户名和密码:
这里写图片描述
为了显示密码我这里没有用密码框了。输入完之后成功登陆
这里写图片描述
接下来正式注入了,用户名输入:’ or 1=1# 密码随便输入
这里写图片描述
点击提交之后:
这里写图片描述
居然登陆成功了。哈哈哈,接下来分析一下注入后SQL语句吧:
我在sql语句那里设置了一个断点,看一下拼接后的sql
这里写图片描述
这里写图片描述
这里可以看到拼接后的sql语句是:
select * from user where username=” or 1=1#’ and password=’202cb962ac59075b964b07152d234b70’这里的#是mysql的注释符,意思就是忽略后面的sql语句,这样的话就不用验证了,而且在username后面还有一句逻辑语句or 1=1,这样的话这条语句永远成立,所以就通过了验证。

接下来就谈谈常见的方SQL注入方法:
1、最常见的就是采用mysqli_real_escape_string函数进行转义一些特殊的字符比如\n、\r、\、’、” 等(在查找mysql_real_escape_string函数的时候发现PHP文档说这个函数在php5.5之后就被抛弃了,改用mysqli_real_escape_string,看来PHP要全面使用面向对象的mysqli了),就像刚才的注入有个单引号,用了这个函数之后就会被转义,这样拼接就失败了。我们来看看再用之前的’ or 1=1#去拼接,加入这个函数之后会怎样:

      $name=mysqli_real_escape_string($mysqli,$_POST['username']);      //必须使用数据库连接,这样看来是专门为防sql注入准备的,比较安全      $pwd=mysqli_real_escape_string($mysqli,md5($_POST['password']));

这里写图片描述
结果不能登录了,设个断点看一下转义之后sql语句:
这里写图片描述
这个是PHP文档给出的例子

<?php     // Assume this is a simple comments form with a name and comment.     $name = mysqli_real_escape_string($conn, $_POST['name']);     $comments = mysqli_real_escape_string($conn, $_POST['comments']);     // Here is where most of the action happens.  But see note below     // on dumping back out from the database     // We should use the ENT_QUOTES flag second parameter...     $name = htmlspecialchars($name);     $comments = htmlspecialchars($comments);     $insert_sql = "INSERT INTO tbl_comments ( c_id, c_name, c_comments ) VALUES ( DEFAULT, '" . $name . "', '" . $comments . "')";     $res = mysqli_query($conn, $insert_sql);     if ( $res === false ) {          // Something went wrong, handle it     }     // Now output page showing comments?>

看到单引号‘被转义成了/’了这样的话拼接就没用了。
二、打开magic_quotes_gpc来防止SQL注入
这个原理跟第一个的原理类似,是将GET、POST、COOKIE传过来的数据进行自动转义,相当于用addslshes()函数进行转义。但是这种方式没有办法防止当参数是数字型的sql攻击,因为数字是没有单引号或者双引号的。解决的办法是用intaval()函数强制将字符数据转换成数字。如果开启了magic_quotes_gpc=on,在第一个方法中记得用stripslashes函数去掉/
三、自定义过滤函数
以下是W3C给出的一个过滤函数我将转义函数改了

function check_input($value,$con){// 去除斜杠if (get_magic_quotes_gpc())  {  $value = stripslashes($value);  }// 如果不是数字则加引号if (!is_numeric($value))  {  $value = "'" . mysqli_real_escape_string($con,$value) . "'";  }return $value;}

这个函数考虑到使用mysqli_real_escape_string比使用addslshes()更加安全

最后注意了:
在写这篇文章的时候,笔者参考了一篇文章说sql注入可以绕开以上的方法了,吓得得我一身冷汗,看了之后果然觉得厉害。文章中建议使用不要用mysql_query了而是用PDO和MYSQLi来代替mysql_query,心想还好我用的是mysqli,它采用了mysqli的Prepared Statement机制可以有效解决sql注入。大家可以参考一下
文章地址:参考文章

总结:
1、sql注入的方式其实很简单,但是后果却是很致命的,所以开发人员一定记住永远不要去相信客户的数据。
2、防sql注入的方法有很多,但是一定得保持一定得技术更新,因为黑客的技术越来越厉害了,要经常更新这方面的防护知识,随时保持最新的防漏洞知识。

0 0
原创粉丝点击