万能密码的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 相关文章推荐
SQL Server数据定义——模式与基本表操作
Apr 05 SQL Server
SQL Server 数据库实验课第五周——常用查询条件
Apr 05 SQL Server
SQL Server连接查询的实用教程
Apr 07 SQL Server
SqlServer数据库远程连接案例教程
Jul 15 SQL Server
sql通过日期判断年龄函数的示例代码
Jul 16 SQL Server
sql server 累计求和实现代码
Feb 28 SQL Server
详解在SQLPlus中实现上下键翻查历史命令的功能
Mar 18 SQL Server
sql server偶发出现死锁的解决方法
Apr 10 SQL Server
如何使用SQL Server语句创建表
Apr 12 SQL Server
SQL Server中使用表变量和临时表
May 20 SQL Server
SQL SERVER中的流程控制语句
May 25 SQL Server
SQL Server使用CROSS APPLY与OUTER APPLY实现连接查询
May 25 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
了解咖啡雨林联盟认证 什么是雨林认证 雨林认证是什么意思
2021/03/05 新手入门
PHP 开发环境配置(Zend Server安装)
2010/04/28 PHP
Locate a File Using a File Open Dialog Box
2007/06/18 Javascript
什么是JavaScript
2009/08/13 Javascript
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
javascript hasFocus使用实例
2010/06/29 Javascript
javascript学习笔记(十) js对象 继承
2012/06/19 Javascript
jqTransform form表单美化插件使用方法
2012/07/05 Javascript
js鼠标滑轮滚动事件绑定的简单实例(兼容主流浏览器)
2014/01/14 Javascript
JS实现仿QQ聊天窗口抖动特效
2015/05/10 Javascript
JavaScript去除数组里重复值的方法
2015/07/13 Javascript
javascript实现将文件保存到本地方法汇总
2015/07/26 Javascript
JS基于VML技术实现的五角星礼花效果代码
2015/10/26 Javascript
js数组去重的5种算法实现
2015/11/04 Javascript
JavaScript学习笔记之取数组中最大值和最小值
2016/03/23 Javascript
jQuery qrcode生成二维码的方法
2016/04/03 Javascript
js获取上传文件的绝对路径实现方法
2016/08/02 Javascript
JavaScript中函数声明与函数表达式的区别详解
2016/08/18 Javascript
Vue DevTools调试工具的使用
2017/12/05 Javascript
VUE + UEditor 单图片跨域上传功能的实现方法
2018/02/08 Javascript
vue实现移动端轻量日期组件不依赖第三方库的方法
2019/04/28 Javascript
解决vue watch数据的方法被调用了两次的问题
2020/11/07 Javascript
简单掌握Python的Collections模块中counter结构的用法
2016/07/07 Python
Tensorflow分类器项目自定义数据读入的实现
2019/02/05 Python
pandas 使用均值填充缺失值列的小技巧分享
2019/07/04 Python
python openpyxl使用方法详解
2019/07/18 Python
如何将 awk 脚本移植到 Python
2019/12/09 Python
jupyter notebook 实现matplotlib图动态刷新
2020/04/22 Python
Python实现播放和录制声音的功能
2020/08/12 Python
css3新单位vw、vh的使用教程
2018/03/23 HTML / CSS
岗位聘任书范文
2014/03/29 职场文书
镇班子对照检查材料思想汇报
2014/09/24 职场文书
党员反对四风思想汇报范文
2014/10/25 职场文书
学校群众路线专项整治方案
2014/10/31 职场文书
干部年终考核评语
2015/01/04 职场文书
2015年银行员工工作总结
2015/04/24 职场文书