【网络安全 | SQL注入】一文讲清预编译防御SQL注入原理

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 【网络安全 | SQL注入】一文讲清预编译防御SQL注入原理

在防止SQL注入的方法中,预编译是十分有效的,它在很大程度上解决了SQL注入问题。

SQL注入简析

数据库查询语句未对SQL注入做任何防护时,语句基本如下:

$name=$_POST['name'];  
$pass=$_POST['pass']; 
$sql="SELECT * FROM user WHERE name='$name' AND pass='$pass'";

当我们提交name=-1' union select 1,user()# pass=12时,后端查询语句变为:

$sql="SELECT * FROM user WHERE name='-1' union select 1,user()#' AND pass='12'";

等价于

$sql="SELECT * FROM user WHERE name='-1' union select 1,user()

由于数据库中没有id='-1’的数据项,此半句运行结果为FALSE,页面不会显示任何内容;后半句union select 1, 2, user(),表示联合查询当前的用户名,此半句运行结果为True,此时页面显示当前登录数据库的用户名(此为敏感信息)

也就是说,这导致了SQL的语法结构被更改,从而实现了命令执行:

而预编译能防止SQL语法结构被更改,它是怎么实现的呢?

在此之前,我们需要了解什么是预编译。

预编译

预编译又称为预处理,顾名思义,就是为代码编译做的预备工作。预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。

举个例子,很多情况下,一条SQL语句可能会反复执行,或者每次执行的时候只有个别的参数值不同,如:

SELECT username, password FROM users WHERE id=121;
SELECT username, password FROM users WHERE id=1532;
SELECT username, password FROM users WHERE id=1123;
SELECT username, password FROM users WHERE id=121;
SELECT username, password FROM users WHERE id=121;
...

这些语句的语法树相同,但每次都要进行重复的编译,导致数据库运行效率低下。

预编译语句将以上语句中的值用占位符?替代,即将SQL语句模板化或者参数化,SQL语句先交由数据库预处理,构建语法树,再传入真正的字段值多次执行,省却了重复解析和优化相同语法树的时间,提升了SQL执行的效率。

简要来说就是:一次编译多次运行

预编译如何防止SQL注入

那么这和预防SQL注入有何联系?

在预编译的机制下,用户在向原有SQL语句传入值之前,原有SQL语句的语法树就已经构建完成,因此无论用户输入什么样的内容,都无法再更改语法树的结构。至此,任何输入的内容都只会被当做值来看待,不会再出现非预期的查询,这便是预编译能够防御SQL注入的根本原因。

预编译代码如下:

$name = $_POST['name'];
$pass = $_POST['pass'];
$stmt = $conn->prepare("SELECT * FROM user WHERE name=? AND pass=?");// 准备 SQL 查询语句,用于验证用户名和密码
$stmt->bind_param("ss", $name, $pass);// 绑定参数,防止 SQL 注入攻击
$stmt->execute();// 执行查询
$result = $stmt->get_result();// 获取查询结果集
if ($result->num_rows > 0) {
    // 用户验证成功

当我们提交name=1' union select 1,user()# pass=12时,由于预编译的存在,后端查询语句变为:

SELECT * FROM user WHERE name='1' union select 1,user()#' AND pass='12'

由于输入的内容都只会被当做值来看待,所以并不会导致恶意查询。

读者可以将sqli-labs的第一关(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.
$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>

尝试注入,可以发现并不能成功。

然而,预编译语句并不适用于所有参数。在某些特定的场景下,如动态表名、动态列名或排序方式等,无法使用占位符进行替代,因为它们不属于参数值。一种常见的做法是执行输入验证和过滤,确保用户提供的数据符合预期的格式和规范。例如,可以使用白名单机制来限制可接受的表名和列名,或者通过预定义的选项来控制排序方式。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
8月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
11月前
|
SQL 安全 关系型数据库
SQL注入之万能密码:原理、实践与防御全解析
本文深入解析了“万能密码”攻击的运行机制及其危险性,通过实例展示了SQL注入的基本原理与变种形式。文章还提供了企业级防御方案,包括参数化查询、输入验证、权限控制及WAF规则配置等深度防御策略。同时,探讨了二阶注入和布尔盲注等新型攻击方式,并给出开发者自查清单。最后强调安全防护需持续改进,无绝对安全,建议使用成熟ORM框架并定期审计。技术内容仅供学习参考,严禁非法用途。
1705 0
|
10月前
|
SQL 存储 自然语言处理
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
|
11月前
|
SQL 人工智能 自然语言处理
Text2SQL圣经:从0到1精通Text2Sql(Chat2Sql)的原理,以及Text2Sql开源项目的使用
Text2SQL圣经:从0到1精通Text2Sql(Chat2Sql)的原理,以及Text2Sql开源项目的使用
Text2SQL圣经:从0到1精通Text2Sql(Chat2Sql)的原理,以及Text2Sql开源项目的使用
|
SQL 缓存 Java
框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性
本文详细解构了MyBatis的工作机制,包括解析配置、创建连接、执行SQL、结果封装和关闭连接等步骤。文章还介绍了MyBatis的五大核心功能特性:支持动态SQL、缓存机制(一级和二级缓存)、插件扩展、延迟加载和SQL注解,帮助读者深入了解其高效灵活的设计理念。
|
SQL 程序员 安全
|
SQL 安全 程序员
|
SQL 测试技术 数据库