php+sql+防注入正则表达式,SQL防注入

本文探讨了动态SQL查询的编写技巧,强调了SQL注入的危害,并介绍了参数化查询作为安全解决方案。通过实例解析了如何避免引号问题和处理复杂参数,同时提到了在特定场景下可能需要考虑直接插入变量的情况,以及用户输入处理的最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标:编写动态的SQL查询

动态查询即是指将变量放到语句中,将固定的字符串和变量拼接在一起,组成一个完整的SQL查询语句,由于变量的值是动态变化的,因此查询也是动态的。编写这样的能够执行的动态的查询语句是十分自然的,也非常方便。但是,不经思考的加入也会带来很大的安全隐患。例如这样的一个查询:

SELECT × FROM Bugs WHERE bug_id = $bug_id";

如果这个时候$bug_id = "1234; DELETE FROM Bugs",Bugs表就跪了。因此SQL注入的危害相当大,不能将未经验证的输入作为代码执行。

做法

没有一种技术能够完全的抵抗SQL注入,因此,需要将多种做法结合起来

转义

转移能防止一些意外的情况,例如这个查询:

SELECT * FROM Projects WHERE project_name = '$project_name'

如果$project_name = O'Hare(这是很正常的一种情况),由于名字里面有个引号,查询就变成:

SELECT * FROM Projects WHERE project_name = 'O'Hare'

这个时候数据库就会因为多了个引号而出错,因此需要在名字里面的'前加反斜杠。

参数化查询

参数化查询是指在编写查询语句的时候,在需要参数的位置上使用参数占位符,然后查询的时候提供这一参数。以php为例:

$sql = "SELECT * FROM Projects WHERE project_name = ?";

$stmt = mysqli_prepare($con, $sql);

mysqli_stmt_bind_param($stmt, 's', $_POST['name']);

mysqli_stmt_execute($stmt);

简单来说,数据库接到一个指令,大致是这么做的:

编译SQL生成执行计划

选择执行计划

执行

SQL注入很多情况是增加查询语句,增加查询语句就会造成查询的语义发生变化(就是说编译会生成不同的东西)。如果使用参数化查询,在准备查询语句的时候数据库就去编译,然后提供参数就会重用这个编译结果,即使使用了注入变量,语义也不会发生变化(不会重新编译),同时,传参的时候,数据库也会将变量进行过滤,以达到防止注入的效果。

参数化查询也有做不到的东西:

1.多个值的列表不能作为单一参数

如果编写这么一个查询:

SELECT * FROM Bugs WHERE bug_id IN (?)

那么你传递参数的时候不能是“1234,3456,5678”这样的,这样会被认为是一个字符串

2.表名,列名,SQL关键字不能作为参数

过滤输入内容

应该将所有不合法的字符去掉,而不是找是否有些输入包含了危险的内容。

比如说如果是需要一个整数,就应该只是用变量里面的整数部分,(在Php里面有filter扩展),可以直接用类型转换函数,也可以用正则表达式匹配

给动态输入的值加引号

一般都用参数化查询,但是有时候,参数化查询会导致数据库采用错误的优化方案(可能是采用错误的索引)。比如说表里面有一列99%的都是TRUE,那么用所以很快就能查询到那1%的FALSE。这个时候将变量直接插进去是好的做法。但这个时候就要格外小心的引用字符串。在php里面可以使用PDO::quote()

用户与代码的隔离

比如说,你想要让用户选择到底是按什么关键字排序,是升序排序,还是按降序排序,这个时候你从客户端接受两个参数

$sort_standard = $_POST['order'];

$direction = $_POST['direction'];

$sql = "SELECT * FROM Bugs ORDER BY $sort_standard $direction";

mysqli_query($con, $sql);

但是这个并不是一个安全的做法,因为用户可以传递任意值。但是参数化查询又不能是关键字,采用这样的做法:

先声明$sort_standard和$direction数组,比如这样

$sort_standard = array(

"status" => "status",

"date" => "date_report"

);

$direction = array(

"up" => "ASC",

"down" => "DESC"

);

当判断到用户的选择不在数组中的时候就使用默认值,如果在数组中就用对应值,这样做:

从不使用用户的输入进行查询,减少了注入风险

让语句动态化,而没有语法上的限制

将数据库查询和用户界面解藕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值