【网络安全 | SQL注入】一文讲清预编译防御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 复制代码
$sql="SELECT * FROM user WHERE name='-1' union select 1,user()#' AND pass='12'";

等价于

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

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

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

而预编译能防止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注入的根本原因。

预编译代码如下:

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时,由于预编译的存在,后端查询语句变为:

sql 复制代码
SELECT * FROM user WHERE name='1' union select 1,user()#' AND pass='12'

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

读者可以将sqli-labs的第一关(Less-1)的index.php修改为:

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> 

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

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

相关推荐
祁白_20 小时前
文件包含笔记整理
笔记·学习·安全·web安全
恃宠而骄的佩奇20 小时前
网络安全面试题——安全服务
web安全·网络安全·面试·奇安信
乾元20 小时前
当奥本海默遇到图灵:AI 开启的网络安全新纪元
服务器·网络·人工智能·网络协议·安全·web安全
lifejump1 天前
Pikachu | XXE
服务器·web安全·网络安全·安全性测试
香气袭人知骤暖1 天前
SQL慢查询常见优化步骤
android·数据库·sql
Star Learning Python1 天前
MySQL日期时间的处理函数
数据库·sql
醇氧1 天前
SqlLogInterceptor mybatis配置打印SQL
java·sql·mybatis
恃宠而骄的佩奇2 天前
蚁剑 php一句话木马简单免杀(编码)绕过360,火绒
开发语言·web安全·php·免杀·一句话木马·火绒安全
清风拂山岗 明月照大江2 天前
MySQL进阶
数据库·sql·mysql
知识分享小能手2 天前
Oracle 19c入门学习教程,从入门到精通,SQL*Plus命令详解:语法、使用方法与综合案例 -知识点详解(4)
sql·学习·oracle