预编译防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;
#带入变量执行语句

为什么可防止ql注入
@varibleName2="-2 union select 1,2,3,database()"

查询结果为空,因为这里是直接去找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");#使用占位符

浙公网安备 33010602011771号