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

昨天被某大牛问了一个问题,为什么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跑类似),就这一步,就将本批查询语句的语义固化成了一套行为动作,这套行为动作正是所谓的“执行计划”,执行计划描述的东西大概是从什么地方取数据、如何处理数据等等,这也是为什么表名、字段名不能参数化的原因,因为这些东西都不确定的话根本没法生成执行计划。至于参数的值有没有影响执行计划的生成,是有的,但它影响的是这个值能否命中某个索引、统计信息等性能相关的东西,能的话就生成更优的执行计划(精确指引到某个页取数据之类),否则走笨方法(如全表扫描),而不会对整套计划的纲领造成影响,这个就是参数化能防注入的原因所在。

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

原文地址:https://www.cnblogs.com/manmanrenshenglu/p/9013079.html

时间: 2024-10-11 17:45:24

为什么参数化查询可以防止SQL注入?(转)的相关文章

参数化查询为什么能够防止SQL注入

很多人都知道SQL注入,也知道SQL参数化查询可以防止SQL注入,可为什么能防止注入却并不是很多人都知道的. 本文主要讲述的是这个问题,也许你在部分文章中看到过这块内容,当然了看看也无妨. 首先:我们要了解SQL收到一个指令后所做的事情: 具体细节可以查看文章:Sql Server 编译.重编译与执行计划重用原理 在这里,我简单的表示为: 收到指令 -> 编译SQL生成执行计划 ->选择执行计划 ->执行执行计划. 具体可能有点不一样,但大致的步骤如上所示. 接着我们来分析为什么拼接SQ

参数化查询为什么能够防止SQL注入 (转)

很多人都知道SQL注入,也知道SQL参数化查询可以防止SQL注入,可为什么能防止注入却并不是很多人都知道的. 本文主要讲述的是这个问题,也许你在部分文章中看到过这块内容,当然了看看也无妨. 首先:我们要了解SQL收到一个指令后所做的事情: 具体细节可以查看文章:Sql Server 编译.重编译与执行计划重用原理 在这里,我简单的表示为: 收到指令 -> 编译SQL生成执行计划 ->选择执行计划 ->执行执行计划. 具体可能有点不一样,但大致的步骤如上所示. 接着我们来分析为什么拼接SQ

EntityFramework Core 2.0执行原始查询如何防止SQL注入?

前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramework Core执行原始查询 在EntityFramework Core中执行原始查询我们借助FromSql来实现,如下: using (var context = new EFCoreDbContext()) { var orders = context.Orders .FromSql("SELECT

Java代码审计连载之—SQL注入

前言近日闲来无事,快两年都没怎么写代码了,打算写几行代码,做代码审计一年了,每天看代码都好几万行,突然发现自己都不会写代码了,真是很DT.想当初入门代码审计的时候真是非常难,网上几乎找不到什么java审计的资料,摸索了很长时间,搜到的也仅仅讲了点原理,为了给想学java代码审计的朋友门一点入门资料,就开始写<java代码审计连载>系列文章,本文章适合初学者,大牛留下脚印后请绕过,若代码有什么其他问题请忽略,因为那不是重点,此片只讲述SQL注入.本次写了两个简单的页面,一个登陆页面,一个查询id

如何向非技术人(程序猿)解释SQL注入?

前两天看博客园新闻,有一篇文章名为<我该如何向非技术人解释SQL注入?>(http://kb.cnblogs.com/page/515151/).是一个外国人写的,伯乐在线翻译的.我当时看了一下,觉得蛮通俗易懂的,对于不懂编写程序及数据库SQL语言的人来说,理解应该没有问题. 今天早上上班坐地铁,看到糗百里的一个段子(原谅一个程序猿看跟编程技术不相关网站行为),笑过之后脑海中突然就跳出了这几个字“SQL注入”!先把那个段子Copy一份,大家先轻松一下: 一哥们是送快递的,一天送快递到人家楼下,

参数化查询比拼接字符串慢的原因

我们都知道,参数化查询可以处理SQL注入,以及提高查询的效率,因为参数化查询会使MSSQL缓存查询的计划. 但是现在我发现一个奇怪的问题,就是参数化查询比字符串拼接要慢,而且速度相差10倍之多. SQL语句是: select * from T_Message where T_Message.BelongTo=@BelongTo 开始在ADO.NET中用SqlParameter传递参数@BelongTo时是这么写的 SqlParameter param1 = new SqlParameter("@

SQL注入攻与防之代码层防御SQL注入

[目录] 0x0 前言 0x1 领域驱动的安全 1.1 领域驱动的设计 1.2 领域驱动的安全示例 0x2 使用参数化查询 2.1 参数化查询 2.2 Java中的参数化语句 2.3 .NET(C#)中的参数化语句 2.4 PHP中的参数化语句 2.5 PL/SQL中的参数化语句 0X3 移动应用中的参数化语句 3.1 iOS应用程序中的参数化语句 3.2 Android应用程序中的参数化语句 3.3 HTML浏览器中存储的参数化语句 0x4 输入验证 4.1 白名单 4.2 黑名单 4.3 J

SQL注入与防范

SQL注入简介: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句. SQL注入方法: 一.拼接字符串(通过输入框输入SQL语句使其改变原意) Select * from T_User where UserID

怎样写防止Sql注入的Sql语句

1.什么是SQL注入 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 2.如何防止SQL注入 防止SQL注入的方法有两种: a.把所有的SQL语句都存放在存储过程中,这样不但可以避免SQL注入,还能提高一些性能,并且存储过程可以由专门的数据库管理员(DBA)编写和集中管理,不过这种做法有时候针对相同的几个表有不同条件的查询,SQL语句可能不同,这样就会编写大量的存储过程. b.使用参数化SQL查询语句. 3.为什