首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >预编译为什么可以防御 SQL 注入 ?

预编译为什么可以防御 SQL 注入 ?

作者头像
信安之路
发布2024-11-22 20:32:08
发布2024-11-22 20:32:08
32900
代码可运行
举报
文章被收录于专栏:信安之路信安之路
运行总次数:0
代码可运行

预编译最初的目的是提高代码的复用性,因为有很多只有参数值不同的 SQL(完全相同的 SQL 会从缓存里查),比如:

select * from user where id='1'

select * from user where id='2'

这些 SQL 的语法树相同,但每次都要进行重复的编译,很浪费时间。

而预编译可以将 SQL 语句模板化,值的位置用占位符替代,这样数据库就会事先编译好 SQL 语法结构,等真正调用的时候,再传入值执行,省掉了重复建立语法树的时间。

select * from user where id={占位符}

通过抓包来看,SQL 语句先被预编译(Prepare Statement),参数值先用占位符替代。等执行(Execute Statement)的时候,再传入参数。

用户传入的参数不参与语法树的构建,就改不了 SQL 的语法结构,也就避免了注入。

以 MyBatis(半自动化的持久层框架)为例,#{id} 这种格式传参,会先把 SQL 传给数据库进行预编译,等调用的时候,再用参数替换掉占位符,然后执行。

代码语言:javascript
代码运行次数:0
运行
复制
<select id="getUser" resultType="Blog" parameterType=”int”>         SELECT *         FROM user     WHERE id=#{id}</select>

但有些 SQL 需要使用动态表名和列名,这种时候就不能使用预编译了,需要把 #{id} 换成 ${id},这样参数就会直接参与 SQL 编译,无法防止 SQL 注入,这时候就要手动过滤参数了。

提示:MyBatis 框架的预编译,是 JDBC 中的 PreparedStatement 类在起作用,它的对象包含了编译好的 SQL 语句。

PHP 中使用 MySQL 的预编译功能:

1)定义预编译的 SQL 语句,参数用占位符 ? 表示

$sql = "SELECT * FROM user WHERE id= ? ";

2)创建预处理对象

mysqli_stmt = mysqli->prepare(

3)绑定参数

mysqli_stmt->bind_param('i',

4)绑定结果集

mysqli_stmt->bind_result(

5)执行

$mysqli_stmt->execute();

预编译的局限性

预编译的机制是先编译,再传值,用户传递的参数无法改变 SQL 语法结构,从根本上解决了 SQL 注入的问题。

但并不是所有参数都可以使用预编译,比如动态表名和列名的场景,因为语义分析时,会解析语法树,检查表名和列名是否存在,所以表名和列名不能被占位符替代,也就没法使用预编译。

同理,排序场景的 ASC/DESC 也需要动态传参,不能使用预编译。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 信安之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 预编译的局限性
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档