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

2 篇文章 0 订阅
2 篇文章 0 订阅
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值