万能密码的SQL注入漏洞其PHP环境搭建及防御手段

编辑: admin 分类: mssql 发布时间: 2021-11-16 来源:互联网
目录
  • 万能密码的SQL注入漏洞其PHP环境搭建及防御手段
    • 一、环境搭建
    • 二、session会话
    • 三、环境搭建代码
      • 1、创建数据库脚本
      • 2、登录界面html
      • 3、查询数据库是否为正确的账号密码php代码
      • 4、连接数据库php代码:
      • 5、注销登录代码(即关闭session会话)
      • 6、登录成功欢迎界面
    • 四、万能密码漏洞剖析
      • 五、万能密码攻击防护
        • 1、使用正则表达式限制用户输入
        • 2、使用PHP转义函数
        • 3、转义函数的弊端
      • 六、MySQLi 参数化查询

      万能密码的SQL注入漏洞其PHP环境搭建及防御手段

      一、环境搭建

      这个渗透环境的搭建有以下几点:

      • 基于session的会话
      • 登录界面
      • 登录成功界面
      • 注销界面
      • 数据库搭建
      • 数据库连接

      二、session会话

      • 服务器端利用session_start()函数发起一次session的会话
      • 此时我们登录成功后用户的数据被保存在服务器端的Cookie: session= ,即sessionID
      • 如果需要再次访问
      • 服务器端的$_SESSION['...']会获取用户session
      • 然后与原本存在于服务器的sessionID进行比对,如果比对成功,则证明用户正确

      三、环境搭建代码

      1、创建数据库脚本

      在MySQL中使用source命令即可运行脚本:

      drop database if exists lab;
      create database lab;
      use lab;
      
      create table users
      (
          id int not null auto_increment,
          username char(32) not null,
          passcode char(32) not null,
          primary key(id)
      );
      
      insert into users(username,passcode) values('admin','admin123');
      insert into users(username,passcode) values('alice','alice456');
      

      2、登录界面html

      <html>
      
      <head>
          <meta charset="UTF-8">
          <title>Login</title>
          <style>
              #a {
                  width: 500px;
                  text-align: center;
              }
              
              .b {
                  width: 200px;
                  height: 30px;
              }
          </style>
      </head>
      
      <body>
          <div id=a>
              <h2>Login!</h2>
              <form name="form_login" method="POST" action="check_login.php">
                  Username:<input type="text" class="b" name="username" /><br> <br> 
        Password:<input type="password" class="b" name="password" /><br>
                  <input type="submit" name="Submit" value="Submit" />
                  <input type="reset" name="reset" value="Reset" />
              </form>
          </div>
      </body>
      
      </html>
      
      

      3、查询数据库是否为正确的账号密码php代码

      <?php
      include('con_database.php');
      
      $username=isset($_POST['username'])?$_POST['username']:'';
      $password=isset($_POST['password'])?$_POST['password']:'';
      if($username=='' || $password==''){
          echo "<script>alert('请输入账号和密码!')</script>";
          exit;
      }
      
      $sql="select * from users where username='$username' and passcode='$password'";
      
      $query=mysqli_query($con,$sql) or die('SQL语句执行失败'.mysqli_error($con));
      if ($row=mysqli_fetch_array($query)){
          session_start();
          $_SESSION['username']=$row[1];
          echo "<a href='welcome.php'>欢迎访问</a>";
      }else{
          echo "<script>alert('登录失败!');history.go(-1)</script>";
      }
      mysqli_close($con);
      ?>
      
      
      

      4、连接数据库php代码:

      <?php
      $con=mysqli_connect('127.0.0.1','root','root') or die("数据库连接失败!");
      mysqli_select_db($con,'lab')or die("数据库连接失败");
      ?>

      5、注销登录代码(即关闭session会话)

      <?php
      session_start();
      session_unset();
      session_destroy();
      echo "注销成功";
      ?>

      6、登录成功欢迎界面

      <?php
      session_start();
      if(isset($_SESSION['username'])){
          echo "欢迎用户".$_SESSION['username']."登录";
          echo "<br>";
          echo "<a href=logout.php>退出登录</a>";
      }else{
          echo "您没有权限访问";
      }
      ?>
      
      
      

      至此,我们的渗透环境就构建好了

      四、万能密码漏洞剖析

      • 用户名输入' or 1=1 or',密码随意,发现可以登录进去
      • 密码输入 'or '1=1 也可以登录进去

      当然登录方法不止一种:

      原来查询语句是这样的:

      $sql="select * from users where username='$username' and passcode='$password'";

      经过注入之后,变成:

      $sql="select * from users where username='' or 1=1 or ' and passcode='****'";

      我们观察到,where后面呃字句中的username被闭合,并且字句分成三个句子并用or连接。
      在SQL语句中 and的优先级要大于or,所以1=1先判断,为真,即where后面的语句为真,即整个SQL语句为真,即表示查询正确
      而形成的语句可以将整个users表查询,后面的$row=mysqli_fetch_array($query)选择的是查询的第一行值,这样满足了SQL语句并跳过了登录验证
      由此可以引申出,只要where后面字句为真,即可跳过验证,有如下衍生方法:

      • ' or 1=1 #
      • ' or 1=1 -- (后面有空格)
      • 'or"="or'

      五、万能密码攻击防护

      1、使用正则表达式限制用户输入

      可以使用正则表达式限制用户的用户名输入,比如:/^[a-z0-9A-Z_]{5,16}$/
      这个限制了用户5位以上16位以下的字母数字下划线为用户名的输入
      这个限制在check_login.php中添加

      <?php
      include('con_database.php');
      
      $username=isset($_POST['username'])?$_POST['username']:'';
      $password=isset($_POST['password'])?$_POST['password']:'';
      if (!preg_match("/^[a-Z0-9A-Z_]{5,16}$/",$username)){
          echo "<script>alert('用户名格式错误')</script>";
          exit;
      
      if($username=='' || $password==''){
          echo "<script>alert('请输入账号和密码!')</script>";
          exit;
      }
      
      $sql="select * from users where username='$username' and passcode='$password'";
      
      $query=mysqli_query($con,$sql) or die('SQL语句执行失败'.mysqli_error($con));
      if ($row=mysqli_fetch_array($query)){
          session_start();
          $_SESSION['username']=$row[1];
          echo "<a href='welcome.php'>欢迎访问</a>";
      }else{
          echo "<script>alert('登录失败!');history.go(-1)</script>";
      }
      mysqli_close($con);
      }
      ?>
      

      2、使用PHP转义函数

      • addslashes()函数:能够将单引号、双引号、反斜杠和null转义
      • mysql_escape_string()函数、mysql_real_escape_string()函数这个是转义SQL语句中的符号,php7.x版本的都要变成mysqli
      bgp服务器http://www.558idc.com/yz.html
      $username=isset($_POST['username'])?addslashes($_POST['username']):'';
      $password=isset($_POST['password'])?mysqli_real_escape_string($con,$_POST['password']):'';
      
      

      3、转义函数的弊端

      因为使用的是UTF-8编码,不是宽字节编码,形成的'会被变成%5c%27
      Windows下默认的是宽字节的gbk编码
      如果在%5c前面加上一个字符形成一个复杂的汉字,那么单引号仍然会被输出

      六、MySQLi 参数化查询

      在使用参数化查询的情况下,服务器不会将参数的内容是为SQL指令中的一部分
      而是在数据库完成SQL指令的编译之后,再代入参数运行
      此时就算参数里面有恶意数据
      但是此时SQL语句以及编译完成
      就不会被数据库运行

      PHP提供了三种访问mysql数据库的拓展:

      • MySQL (PHP5.5起,已经废除)
      • MySQLi
      • PDO(PHP Data Object PHP数据对象)

      PDO和MySQLi提供面向对象的api
      MySQLi也存在面向过程的api,所以容易从MySQL转换到MySQLi

      下面是mysqli形式的check_login.php 写法,新建check_login_mysqli.php

      <?php
      include('con_database.php');
      
      $username=isset($_POST['username'])?$_POST['username']:'';
      $password=isset($_POST['password'])?$_POST['password']:'';
      
      if($username==''||$password==''){
          echo "<script>alert('错误!');history.go(-1);</script>";
          exit;
      }
      $sql="select * from users where username=? and passcode=? ;";//问号表示需要一个参数
      $stmt=$con->prepare($sql);//预编译SQL语句
      if(!$stmt){
          echo 'prepare 执行错误';
      }
      else{
          $stmt->bind_param("ss",$username,$password); //为预编译绑定SQL参数,ss表示两个字符串
          //i——int d——double  s——string   b——boolean
          $stmt->execute();
          $result=$stmt->get_result();
          $row=$result->fetch_row();
          if($row){
              session_start();
              $_SESSION['username']=$row[1];
              echo $row[1]."<a href='welcome.php'>欢迎访问</a>";
          }else{
              echo "<script>alert('登录失败!!');history.go(-1);</script>";
          }
          $stmt->close();
      }
      $con->close();
      ?>
      
      

      一些内容已经标记在代码的注释里面
      参数化的PHP代码真的能够很有效地防止SQL注入。

      以上就是万能密码的SQL注入漏洞其PHP环境搭建及防御手段的详细内容,更多关于万能密码的SQL注入 PHP环境搭建 防御手段的资料请关注hwidc其它相关文章!