正在阅读:

为什么参数化查询可以防止SQL注入?

12,099

昨天被某大牛问了一个问题,为什么SQL参数化查询可以防止SQL注入,参数化查询的原理是什么? 结果闷逼了,之前只知道参数化查询是可以防止SQL注入,但是没有深究其原理,今天就找一些文章,学习一下,也分享给大家。

以下引用知乎大神们的回答:

原理是采用了预编译的方法,先将SQL语句中可被客户端控制的参数集进行编译,生成对应的临时变量集,再使用对应的设置方法,为临时变量集里面的元素进行赋值,赋值函数setString(),会对传入的参数进行强制类型检查和安全检查,所以就避免了SQL注入的产生。

最近在深入学习Java,附上一段实现代码,其他语言把赋值函数的处理封装起来了,导致用户不可见,不能了解其中的机理。

import java.sql.PreparedStatement;

String sql = "select * from user where username=? and passwd=?";
ps = conn.PreparedStatement(sql);
ps.setString(1, "admin");
ps.setString(2, "123456");
resultSet = ps.executeQuery();

具体实现代码参考 Java 的 PreparedStatement (Java Platform SE 7 ) ,其它语言可以对照他的原理进行实现。

参数查询是数据库原生提供的能力,而不是ado.net等数据访问类库提供的,后者只是对前者的封装。我们在程序语言中写的sql语句和参数对象,送到数据库时还是语句和参数,并不是有些答案认为的那样把参数的值转好义后拼接进语句,最后把语句提给数据库。要说类库做了什么“预处理”,大概只是在开发者没有显式指定参数的类型和长度时,类库会根据参数的值自动为其确定合适的类型和长度,仅此而已。这一点用数据库语句跟踪工具(如SQL Server Profiler)很容易证实。所以参数化查询真不关程序语言/类库多少事。

至于数据库接到语句和参数后如何处理,我的理解/猜测是,数据库负责解析查询语句的子系统将语句转换/编译为某种底层的、数据库执行子系统能executing的语言(好比C#编译器把C#编译为IL给CLR跑类似),就这一步,就将本批查询语句的语义固化成了一套行为动作,这套行为动作正是所谓的“执行计划”,执行计划描述的东西大概是从什么地方取数据、如何处理数据等等,这也是为什么表名、字段名不能参数化的原因,因为这些东西都不确定的话根本没法生成执行计划。至于参数的值有没有影响执行计划的生成,是有的,但它影响的是这个值能否命中某个索引、统计信息等性能相关的东西,能的话就生成更优的执行计划(精确指引到某个页取数据之类),否则走笨方法(如全表扫描),而不会对整套计划的纲领造成影响,这个就是参数化能防注入的原因所在。

简单总结,参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物,不会影响行进路线,无非跑的快点与慢点的区别。

参考链接:

占位符,SQL注入?

参数化查询为什么可以防止SQL注入?

目前有:6条访客评论,博主回复2

  1. lz
    2018-03-23 19:08

    在学渗透。不过很多不懂。能大神交流下不。15879440889 微信

  2. 小白
    2018-03-25 10:29

    朋友好难呀,我渗透学了1月了,能有比较好的视频教程不,介绍一下,微信15879440889

    • 独自等待
      2018-03-26 10:24

      兄弟,网上搜索吧,视频还是比较多的。先学会搜索引擎语法

  3. 熊本本
    2018-03-27 11:57

    懂了 谢谢分享

  4. 山下小豆荚

    大神们,求有SQL注入漏洞的网址,我找了两天没找到😂😂

  5. 123
    2018-08-29 14:17

    送达时间

留下脚印,证明你来过。

*

*

流汗坏笑撇嘴大兵流泪发呆抠鼻吓到偷笑得意呲牙亲亲疑问调皮可爱白眼难过愤怒惊讶鼓掌