利用预编译技术防御SQL注入
一、关于SQL注入
众所周知,SQL注入漏洞是一种常见的Web安全漏洞,其形成原因是服务器没有对用户输入的内容进行严格过滤,导致该内容拼接到服务器原本的SQL语句中,被当作SQL语句的一部分执行。
以基于MySQL数据库的开源靶场sqli-labs的第一关(Less-1)为例,我们查看Less-1页面(index.php)的PHP源码:
发现服务器端关键的查询语句是这样两句:
$id=$_GET['id']
SELECT * FROM users WHERE id='$id' LIMIT 0, 1
按照此逻辑,服务器会从URL中获取动态参数id的值,将其赋值给$id这个变量,并将其直接代入到SELECT这条查询语句中去查询资源(即从users表中查询id='$id'的数据项的全部字段),没有对用户输入的id值进行过滤!
正常情况下,如果前端的请求是:
http://.../sqli-labs/Less-1/?id=1
那么,后端的查询语句应该就成了:
SELECT * FROM users WHERE id='1' LIMIT 0, 1
服务器会从users表中查询id='1'(此时数据库把id当成是字符型变量,字符串需要用单引号包裹)的数据项的全部字段,并将其中的一些字段的值回显在页面上,如下图所示:
此时,页面显示了id=1的用户和账号名和密码。
然而,这里的动态参数id对于用户来说是可控的。如果用户精心构造输入,他把前端的请求设置成:
http://.../sqli-labs/Less-1/?id=-1' union select 1, 2, user()--+
那么,后端的查询语句应该就会变成:
SELECT * FROM users WHERE id='-1' union select 1, 2, user()-- ' LIMIT 0,1
由URL中代入进来的加号“+”会被变成空格,而“-- ”(两个减号,后面紧跟一个空格)在SQL语句中表示注释,那么上述查询语句实际上可以简化为:
SELECT * FROM users WHERE id='-1' union select 1, 2, user()
注意看这条查询语句,用户通过精心构造输入(即-1' union select 1, 2, user()--+),使输入的内容代入到原本的SQL语句中并且改变了原本SQL语句的结构——前半句SELECT * FROM users WHERE id='-1',由于数据库中没有id='-1'的数据项,此半句运行结果为FALSE,页面不会显示任何内容;后半句union select 1, 2, user(),表示联合查询当前的用户名(user()是PHP的一个函数,用于显示当前登录数据库的用户名),运行结果为True,此时页面显示当前登录数据库的用户名(此为敏感信息),如图所示:
上述就是通过控制输入构造payload,引发SQL注入攻击的过程。总结一下,那就是攻击者通过精心构造输入,让输入的内容拼接到服务器原本的SQL语句中,改变了原有SQL语句的结构而导致注入攻击。
二、关于SQL语句预编译
(一)什么是预编译
预编译又称为预处理,顾名思义,就是为代码编译做的预备工作。预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
对于数据库来说,通常一条SQL语句从传入到执行经历了以下过程:(1)词法和语义解析优化;(2)制定执行计划;(3)执行并返回结果。这种普通语句称为Immediate Statements。但很多情况下,一条SQL语句可能会反复执行,或者每次执行的时候只有个别的参数值不同,比如:
SELECT username, password FROM users WHERE id=1;
SELECT username, password FROM users WHERE id=2;
这两个SQL语句由于id后的值不同,因此在词法和语义解析优化阶段不会匹配,不能得到重复使用。如果两条语法树相似的SQL语句都需要经过“词法语义解析优化、制定执行计划、执行并返回结果”这样一个过程,则很容易造成时间的浪费、效率的下降。
所谓预编译语句就是将这类语句中的值用占位符(“?”)替代,可以视为将SQL语句模板化或者参数化,即将SQL语句先交由数据库预处理,构建语法树,再传入真正的字段值多次执行,省却了重复解析和优化相同语法树的时间,提升了SQL执行的效率。一般这类语句称为Prepared Statements。
以MySQL为例,利用mysqli的预编译功能编写的核心PHP语句为:
//定义需要预编译的SQL语句,从外界传递的参数(输入)用占位符?表示
$sql = "SELECT * FROM security.users WHERE id= ? LIMIT 0,1";
//创建预处理对象
$mysqli_stmt = $mysqli->prepare($sql);
//绑定参数
$mysqli_stmt->bind_param('i', $id);
//绑定结果集
$mysqli_stmt->bind_result($id, $username, $password);
//执行
$mysqli_stmt->execute();
预编译语句的优势在于:一次编译、多次运行,省去了解析优化等过程。
(二)为什么预编译能够防御SQL注入
上一节中我们说到,SQL注入漏洞产生的原因就是服务器对用户输入的内容没有严格过滤,攻击者通过精心构造输入,让输入的内容拼接到服务器原本的SQL语句中,改变了原有SQL语句的结构,而这个“新”的SQL语句代入到数据库中执行,产生了非预期的结果。
而在预编译的机制下,用户在向原有SQL语句传入输入值之前,原有SQL语句的语法树就已经构建完成,因此无论用户输入什么样的内容,都无法再更改语法树的结构。至此,任何输入的内容都只会被当做值来看待,不会再出现非预期的查询,这便是预编译能够防御SQL注入的根本原因。
三、实战演示
仍然以sqli-labs的第一关(Less-1)为例,Less-1的index.php原始代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-1 **Error Based- String**</title>
</head>
<body bgcolor="#000000">
<div style=" margin-top:70px;color:#FFF; font-size:23px; text-align:center">Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
</font> </div></br></br></br><center>
<img src="../images/Less-1.jpg" /></center>
</body>
</html>
情形一:靶机不做任何防御,此时在攻击机上使用以下payload即可注入成功(获取当前登录数据库的用户名):
http://[靶机IP]/sqli-labs/Less-1/?id=-1' union select 1, 2, user()--+
情形二:靶机利用预编译技术进行防御,index.php原始代码更改为:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-1 **Error Based- String**</title>
</head>
<body bgcolor="#000000">
<div style=" margin-top:70px;color:#FFF; font-size:23px; text-align:center">Welcome <font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">
<?php
//including the Mysql connect parameters.
$sql_server = "localhost";
$sql_username = "root";
$sql_password = "root";
$sql_database = "security";
$mysqli = new mysqli($sql_server, $sql_username, $sql_password, $sql_database);
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
$sql="SELECT * FROM security.users WHERE id= ? LIMIT 0,1";
$mysqli_stmt = $mysqli->prepare($sql); //创建预处理对象
$mysqli_stmt->bind_param('i',$id); //绑定参数
$mysqli_stmt->bind_result($id,$username,$password); //绑定结果集
$mysqli_stmt->execute(); //执行
while($mysqli_stmt->fetch())
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:' . $username;
echo "<br>";
echo 'Your Password:' . $password;
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
</font> </div></br></br></br><center>
<img src="../images/Less-1.jpg" /></center>
</body>
</html>
仍然在攻击机上使用以下payload尝试注入:
http://[靶机IP]/sqli-labs/Less-1/?id=-1' union select 1, 2, user()--+
此时会发现,union select、user()等语句未成功执行,注入不成功。究其原因,靶机的预编译SQL语句将用户输入的内容(即-1' union select 1, 2, user()--+)当成了普通的参数(值),而不是可执行的SQL语句(或SQL语句的一部分)。
本期作者袁泉:深信服安全服务认证专家(SCSE-S),产业教育中心资深讲师,暨南大学网络空间学院校外实践指导老师;曾任职于国防科技大学信息通信学院,从事计算机网络、信息安全专业教学和科研工作十余年,持有HCNA(SECURITY)和HCNA (R&S)证书;熟悉 TCP/IP 协议及网络安全防护体系架构,具有丰富的计算机网络管理、运维与安防实践经验。
利用预编译技术防御SQL注入相关推荐
- mybatis以及预编译如何防止SQL注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedia SQL ...
- 预编译对象解决SQL注入问题
转载于:https://www.cnblogs.com/suanshun/p/6739454.html
- java开发中推荐的防御sql注入方法_SQL 注入防御方法总结
SQL 注入是一类危害极大的攻击形式.虽然危害很大,但是防御却远远没有XSS那么困难. SQL 注入可以参见:https://en.wikipedia.org/wiki/SQL_injection S ...
- java开发中推荐的防御sql注入方法_防御SQL注入的方法总结
SQL 注入是一类危害极大的攻击形式.虽然危害很大,但是防御却远远没有XSS那么困难. SQL 注入漏洞存在的原因,就是拼接 SQL 参数.也就是将用于输入的查询参数,直接拼接在 SQL 语句中,导致 ...
- 5单个编译总会编译全部_JDBC【5】 JDBC预编译和拼接Sql对比
在jdbc中,有三种方式执行sql,分别是使用Statement(sql拼接),PreparedStatement(预编译),还有一种CallableStatement(存储过程),在这里我就不介绍C ...
- javassist技术研究Sql注入检测
AOP为Aspect Oriented Programming的缩写 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术. 日志记录,性能统计,安全控制,事务处理 Java ...
- mysql注入反弹_Discuz!x xss反弹后台无防御sql注入getshell(附带exploit)
### 简要描述: Discuz!x xss反弹后台无防御sql注入getshell,这里的xss只是做一个药引子,因为xss来自日志功能,然而这个日志功能却又默认关闭的,为了测试我们开启它.这个漏洞 ...
- 使用#传递参数防御SQL注入攻击
SQL注入攻击 什么是SQL注入 SQL注入:利用现有应用程序,将(恶意)的SQL命令注入到后台数据库执行一些恶意的操作. 造成SQL注入的原因是因为程序没有有效过滤用户的输入,使攻击者成功的向服务器 ...
- java开发中推荐的防御sql注入方法_Java防止SQL注入
SQL 注入简介: SQL注入是最常见的攻击方式之一,它不是利用操作系统或其它系统的漏洞来实现攻击的,而是程序员因为没有做好判断,被不法用户钻了SQL的空子,下面我们先来看下什么是SQL注入: 比如在 ...
最新文章
- Core ML 文档翻译
- [吴恩达机器学习笔记]12支持向量机3SVM大间距分类的数学解释
- 域名注册商标_科技述说:一起了解网络域名的由来
- 设计模式:结构型模式总结
- return 和 exit
- 【Protocol Buffer】Protocol Buffer入门教程(五):repeated限定修饰符
- excel实战应用案例100讲(十二)-用Excel做一个自动抽奖器
- python设计模式之享元模式
- POJ-2456.Aggressivecows.(二分求解最大化最小值)
- 云效支持自定义构建镜像 征集10家企业免费使用
- 计算机word实训项目任务说明,计算机项目实训报告怎么写啊
- 服务器如何关闭登录日志文件,linux云服务器登录日志文件
- java的dicon文件_配置文件参考
- java关闭服务_实现优雅地关闭Docker中的java服务
- sketch如何做设计稿交互_sketch交互点击视觉标注方法|sketch如何实现交互点击的视觉标注 - PS下...
- latex模板中 引入ORCID链接的方法
- 一文看懂DSP的DMA传输(burst、transfer、wrap)
- 书名:男人一本书 前言
- iis 支持apk json ipa下载
- 前端项目:从0开始实现一个合成大西瓜
热门文章
- Unity3d Ugui 22图集Sprite Packer
- [经验教程]2022天猫淘宝618超级红包预售活动入口是什么时候开始什么时间结束优惠力度大吗及2022天猫淘宝618预售红包活动怎么享受免息分期24期?
- 倩女幽魂2服务器维护怎么抢先进,倩女幽魂OL2月16日服务器维护内容
- win11鼠标灵敏度怎么调 windows11鼠标灵敏度的设置方法
- 用寄存器HAL库完成LED流水灯程序
- C画心形,跳动不停息;黑白字间,情意相随。
- 盲盒源码h5脱单小程序开发
- 寻找SQL执行线索的武器库
- 这30个Python自学网站,再也不用到处找资料啦~
- [附源码]Python计算机毕业设计茶叶产品质量安全可追溯系统