渗透测试-SQL注入-登录漏洞-SQL注入防护


前言

SQL注入-登录漏洞-基础修复中我们提到这个登录页面是存在SQL漏洞的,接下来我们将说说怎么进行SQL注入防护。同时我们还会说到如何防止暴力破解。

引入

登录漏洞:登录界面可以进行SQL注入,轻易实现登录(高)
1、 从代码和SQL语句的逻辑层面进行考虑,让密码对比不轻易失效
2、 基于将用户输入的引号(单引号和双引号)进行转义处理的前提,可以用PHP的内置函数addslashes进行强制转义
另一种方法:可以使用MySQLi的预处理功能达到防SQL注入的目的。

一、登录SQL语句的逻辑问题

//先查用户名对比密码
$sql = "select * from users where username='$username'";
$result = mysqli_query($conn,$sql) or die("SQL语句执行错误");   //result获取到的查询结果,称为结果集

//修复的代码

//认证和授权失败
if(mysqli_num_rows($result) == 1){
  $row = mysqli_fetch_assoc($result);
  //var_dump($row);  //打印
  if ($md5password == $row['password']) {
    echo "login-pass";

    //登录成功后,记录SESSION变量
    $_SESSION['username'] = $username;
    $_SESSION['islogin'] = 'true';

    echo "<script>location.href='welcome.php'</script>";
  }else{
    echo "login-fail";
    echo "<script>location.href='login.html'</script>";
  }   
}else{
  echo "login-fail";
  echo "<script>location.href='login.html'</script>";
}

二、使用addslashes函数

addslashes函数可以将字符串中的单引号、双引号、反斜杠、NULL值自动添加转义字符,从而防止SQL注入中对单引号和双引号的预防。

原始SQL语句如下:
$sql = "select * from users where username='$username' and password='$md5password'";

如果用户输入x' or userid=1#,则SQL语句变成:
$sql = "select * from users where username='x' or userid=1#' and password='$md5password'";

如果使用addslashes函数强制将用户输入的引号添加转义符,则变成:
$sql = "select * from users where username='x\' or userid=1#' and password='$md5password'";
上述SQL语句用户名为:x\' or userid=1#

三、使用mysqli面向对象方式

1.面向过程

$conn = mysqli_connect('127.0.0.1','root','你的数据库密码','learn') or die("数据库连接不成功.");
mysqli_query($conn,"set names utf8");

$sql = "select articleid,author,headline,viewcount,createtime from article where isDelete=1";
$result = mysqli_query($conn,$sql);

// 将数据库查询到的结果集中的数据取出,保存到一个数组中
//$rows = mysqli_fetch_all($result);
//mysqli_fetch_all  默认使用索引数组,也可以设定参数强制使用关联数组
$rows = mysqli_fetch_all($result,MYSQLI_ASSOC);

//遍历结果集数据并输出到页面中
foreach($rows as $row){
    echo $row[0] . '-' . $row[1] . '-' . $row[2] . '-' . $row[3] . '-' . $row[4] . "<br/>";
}

2.面向对象方式

//使用mysqli面向对象方式连接数据库
function create_connection_oop(){
    //连接数据库
    $conn = mysqli_connect('127.0.0.1','root','你的数据库密码','learn') or die("数据库连接不成功.");

    //设置编码格式的两种方式
    $conn->query("set names utf8");
    $conn->set_charset('utf8');
    
    return $conn;
}

四、使用mysql预处理功能

1、 预处理功能的使用

预处理过程就是先把SQL语句交给MySQL数据库处理

//MySQLi预处理功能(面向对象)
function mysqli_prepare_stmt(){
    $conn = create_connection_oop();

    //?在预处理语句中用于代替参数
    $sql = "update users set username = ? where userid = ?";  

    //实例化Prepared Statement与处理对象
    $stmt = $conn->prepare($sql);
    //实例化后需要将参数值进行绑定并在执行时替换
    //bind_param第一个参数是数据类型  i:整数,s:字符串,d:小数,b:二进制
    $stmt->bind_param("si",$username,$userid);
    $username = 'hahasb';
    $userid = 6;

    //正式执行SQL语句
    //$stmt->execute();   //execute()返回布尔类型
    //$conn->commit();    //默认情况下,更新操作会自动提交,也可手工处理

    //如果针对查询语句需进行结果绑定
    $sql = "select * from users where userid < ?";  
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("i",$userid);
    $userid = 6;

    //绑定结果参数
    $stmt->bind_result($userid,$username,$password,$role,$avatar,$createtime);
    $stmt->execute();

    //调用结果并处理
    $stmt->store_result();

    //输出行数
    echo $stmt->affected_rows . "<br/>";
    echo $stmt->num_rows . "<br/>";

    //遍历结果
    while ($stmt->fetch()) {
        echo $userid,$username,$password,'<br/>';
    }

}
mysqli_prepare_stmt();

2、 使用预处理来预防SQL注入

<?php

include "common.php";

//获得用户发送的请求
$username = $_POST['username'];
$password = $_POST['password'];
$vcode = $_POST['vcode'];

//验证码的验证

 if($vcode !== '0000'){
    die("vcode-error");
 }

 $conn = create_connection_oop();

 //md5加密
 $md5password = md5($password);

 //拼接SQL语句并执行它
 //先查用户名对比密码
 $sql = "select userid,username,password,role from users where username=?";

 //绑定查询参数
 $stmt = $conn->prepare($sql);
 $stmt->bind_param("s",$username);

 //绑定结果参数
 $stmt->bind_result($userid,$username2,$password2,$role);

 $stmt->execute();
 $stmt->store_result();


//认证和授权失败
 if($stmt->num_rows == 1){
    $stmt->fetch();
    if ($md5password == $password2) {
      echo "login-pass";

    //登录成功后,记录SESSION变量
    $_SESSION['username'] = $username;
    $_SESSION['islogin'] = 'true';

    echo "<script>location.href='welcome.php'</script>";
    }else{
      echo "login-fail";
      echo "<script>location.href='login.html'</script>";
    }   
 }else{
    echo "login-fail";
    echo "<script>location.href='login.html'</script>";
 }


 //关闭数据库
$conn->close();

?>

3、 配置MySQL临时日志查看SQL语句

在MySQL中运行以下语句,开启临时日志,将日志信息保存到表格mysql数据库的general_log表中(验证防护效果)

# 开启
USE mysql;
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
#  确认
SHOW VARIABLES LIKE “general_log”;

并执行以下语句进行查询确认

SELECT * FROM general_log WHEN argument LIKE "%username%" ORDER BY thread_id DESC LIMIT 10;

完整代码见https://github.com/chengstery/security/tree/main/linux_login

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值