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


Posted in SQL Server onSeptember 04, 2021

万能密码的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
$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环境搭建 防御手段的资料请关注三水点靠木其它相关文章!

SQL Server 相关文章推荐
2021-4-5课程——SQL Server查询【3】
Apr 05 SQL Server
解决sql server 数据库,sa用户被锁定的问题
Jun 11 SQL Server
SQLServer中JSON文档型数据的查询问题解决
Jun 27 SQL Server
SQL Server中使用判断语句(IF ELSE/CASE WHEN )案例
Jul 07 SQL Server
SQL SERVER触发器详解
Feb 24 SQL Server
sql时间段切分实现每隔x分钟出一份高速门架车流量
Feb 28 SQL Server
SQL Server实现分页方法介绍
Mar 16 SQL Server
SQL Server使用导出向导功能
Apr 08 SQL Server
sql server偶发出现死锁的解决方法
Apr 10 SQL Server
SQL Server数据库查询出现阻塞之性能调优
Apr 10 SQL Server
sql server删除前1000行数据的方法实例
Aug 30 #SQL Server
SQLServer之常用函数总结详解
Aug 30 #SQL Server
SQL写法--行行比较
Aug 23 #SQL Server
SQL语句中JOIN的用法场景分析
sql通过日期判断年龄函数的示例代码
Jul 16 #SQL Server
利用 SQL Server 过滤索引提高查询语句的性能分析
SqlServer数据库远程连接案例教程
You might like
多人战的战术与战略
2020/03/04 星际争霸
ThinkPHP的cookie和session冲突造成Cookie不能使用的解决方法
2014/07/01 PHP
PHP中使用asort进行中文排序失效的问题处理
2014/08/18 PHP
JavaScript高级程序设计
2006/12/29 Javascript
Javascript 文件夹选择框的两种解决方案
2009/07/01 Javascript
JavaScript 对象、函数和继承
2009/07/07 Javascript
理解JavaScript变量作用域更轻松
2009/10/25 Javascript
JavaScript.The.Good.Parts阅读笔记(二)作用域&amp;闭包&amp;减缓全局空间污染
2010/11/16 Javascript
Ubuntu 11.10 安装Node.js的方法
2011/11/30 Javascript
jQuery中:focus选择器用法实例
2014/12/30 Javascript
script标签属性用type还是language
2015/01/21 Javascript
基于javascript实现简单的抽奖系统
2020/04/15 Javascript
小白谈谈对JS原型链的理解
2016/05/03 Javascript
JS中的BOM应用
2018/02/02 Javascript
bootstrap 弹出框modal添加垂直方向滚轴效果
2018/07/09 Javascript
LayerClose弹窗关闭刷新方法
2018/08/17 Javascript
vue里面使用mui的弹出日期选择插件实例
2018/09/16 Javascript
浅谈React碰到v-if
2018/11/04 Javascript
WebStorm无法正确识别Vue3组合式API的解决方案
2021/02/18 Vue.js
跟老齐学Python之通过Python连接数据库
2014/10/28 Python
python实现自动重启本程序的方法
2015/07/09 Python
Python实现嵌套列表及字典并按某一元素去重复功能示例
2017/11/30 Python
Python实现连接两个无规则列表后删除重复元素并升序排序的方法
2018/02/05 Python
tensorflow 输出权重到csv或txt的实例
2018/06/14 Python
python对日志进行处理的实例代码
2018/10/06 Python
使用Python批量修改文件名的代码实例
2019/01/24 Python
Python之数据序列化(json、pickle、shelve)详解
2019/08/30 Python
python实现翻译word表格小程序
2020/02/27 Python
css3 border-radius属性详解
2017/07/05 HTML / CSS
详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)
2016/12/15 HTML / CSS
护士实习鉴定范文
2013/12/22 职场文书
护理自荐信
2019/05/14 职场文书
浅谈redis五大数据结构和使用场景
2021/04/12 Redis
python实战之用emoji表情生成文字
2021/05/08 Python
java executor包参数处理功能 
2022/02/15 Java/Android
Spring IOC容器Bean的作用域及生命周期实例
2022/05/30 Java/Android