预编译防sql

参考:

https://forum.butian.net/share/1559

预编译防sql注入

预编译机制可以提升效率,支持预编译机制的数据库有Oracle、Mysql、Microsoft SQL Server、PostgreSQL、MongoDB等。

预编译可以用于防止sql注入,它是先构建语法树,再带入变量

预编译使用

mysql为例

prepare statement_name from "select * from users where id=?";
#statement_name为语句名,?是占位符,上述是构建语法树
set @varibleName=1;
#设置变量名
execute statement_name using @varibleName;
#带入变量执行语句

image-20240222135515399

为什么可防止ql注入

@varibleName2="-2 union select 1,2,3,database()"

image-20240222140116755

查询结果为空,因为这里是直接去找username里面是否有"-2 union select 1,2,3,database()",而不是拼接。

mysqli预编译

<?php
highlight_file(__FILE__);
include('config.php');
$uname = $_GET['uname'];
$conn=mysqli_connect($ip,$username,$password,'test');
$stmt = mysqli_stmt_init($conn);    # 分配并初始化一个语句对象用于mysqli_stmt_prepare()。
mysqli_stmt_prepare($stmt,"select password from users where username = ?");  # 预处理
mysqli_stmt_bind_param($stmt,"s", $uname);   # 绑定

# $stmt->execute(); # 执行
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt,$password);   # 将查询结果绑定至$fraction

if(mysqli_stmt_fetch($stmt)){
    echo '查询成功';
    echo '<br/>';
    echo 'uname: '.$uname;
    echo '<br/>';
    echo 'password: '.$password;
    #print("分数: ".$fraction."\n");
}
else{
    mysqli_stmt_errno($stmt);
}

$conn->close();
?>

PDO预编译

PDO是一个php访问数据库的接口,通过PDO可以访问任何类型数据库,而mysqli只能访问mysql数据库。

<?php
highlight_file(__FILE__);
include('config.php');
$dsn = "mysql:host=$ip;dbname=$dbName";
$conn = new PDO($dsn,$username,$password);
if($conn->errorCode()){
	die($conn->errorInfo());
}
$conn -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "select * from users where username=:name";
$statement = $conn->prepare($sql);
$username1 = $_GET['uname'];
$statement -> bindParam(':name',$username1);
$statement -> execute();

$statement -> bindColumn(1,$passwd);
$statement -> bindColumn(2,$user);
$statement -> bindColumn(3,$id);

while($statement->fetch()){
	echo $id."<br>";
	echo $username1."<br>";
}
$statement = null;
$conn = null;
?>

PDO默认使用模拟预编译,是为了防止一些数据库不支持预编译操作,对于支持预编译的数据库想要使用真正的预编译,需要加一行代码:$conn -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

PDO模拟预处理会自动转义,但是相对没有数据库本身的预编译安全

当PDO::ATTR_EMULATE_PREPARES为false取消模拟预编译,采用本地预编译

当PDO::ATTR_EMULATE_PREPARES为true时采用模拟预编译

预编译被绕过

1.宽字节+PDO模拟预编译:1%df%27%20union%20select%20database();#

2.预编译错误使用:开发者没有使用占位符,仍然是直接带入参数拼接

$stmt = $conn->prepare("select fraction from fraction where name = '$username'");#没使用占位符
$stmt = $conn->prepare("select fraction from fraction where name = :username");#使用占位符
posted @ 2024-03-24 22:27  qingshanboy  阅读(50)  评论(0)    收藏  举报