spring 参数注入 注解化之后还是有sql注入,求教

为什么参数化查询sql能够防止sql注入? - 开源中国社区
当前访客身份:游客 [
当前位置:
就拿php来说吧!
我目前找到的答案是:用参数化查询,数据库不会将参数的内容视为SQL指令的一部份来处理,而是在完成SQL指令的编译后,才套用参数运行。
其实也不是太理解这句话的意思。
共有5个答案
<span class="a_vote_num" id="a_vote_num_
不知道使用过java没有:
PreparedStatement类就是这种。更安全,更高效。
--- 共有 1 条评论 ---
楼主问的是原理,不是实现
(3年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
吃(饭) & & &你可以把饭换成屎或者鸡——巴,都要用你的嘴的。
<span class="a_vote_num" id="a_vote_num_
PDO防注入原理分析以及使用PDO的注意事项
http://my.oschina.net/u/1168437/blog/148432
<span class="a_vote_num" id="a_vote_num_
编译预处理
PreparedStatement
<span class="a_vote_num" id="a_vote_num_
。。。因为如果参数化了,所有真正执行的语句就会变成这样:
select xx from t where t.xx=? and t.yy=? and t.zz like ?。所有的问号就是用户输入的内容,此时是用问号代替的,所以不管用户输入啥,都不会存在sql注入漏洞。
至于那如果这样怎么查询到相应真的需要查的信息呢,那就是一个问号一个问号的向里面再设置进去值了。
更多开发者职位上
有什么技术问题吗?
OSC首席...的其它问题
类似的话题数据库(8)
很多人都知道SQL注入,也知道SQL参数化查询可以防止SQL注入,可为什么能防止注入却并不是很多人都知道的。
本文主要讲述的是这个问题,也许你在部分文章中看到过这块内容,当然了看看也无妨。
首先:我们要了解SQL收到一个指令后所做的事情:
具体细节可以查看文章:Sql Server 编译、重编译与执行计划重用原理
在这里,我简单的表示为: 收到指令 -& 编译SQL生成执行计划 -&选择执行计划 -&执行执行计划。
具体可能有点不一样,但大致的步骤如上所示。
接着我们来分析为什么拼接SQL 字符串会导致SQL注入的风险呢?
首先创建一张表Users:
插入一些数据:
假设我们有个用户登录的页面,代码如下:
验证用户登录的sql 如下:
这段代码返回Password 和UserName都匹配的用户数量,如果大于1的话,那么就代表用户存在。
本文不讨论SQL 中的密码策略,也不讨论代码规范,主要是讲为什么能够防止SQL注入,请一些同学不要纠结与某些代码,或者和SQL注入无关的主题。
可以看到执行结果:
这个是SQL profile 跟踪的SQL 语句。
注入的代码如下:
select COUNT(*) from Users where Password = 'a' and UserName = 'b' or 1=1—'
这里有人将UserName设置为了 “b' or 1=1 –”.
实际执行的SQL就变成了如下:
可以很明显的看到SQL注入成功了。
很多人都知道参数化查询可以避免上面出现的注入问题,比如下面的代码:
实际执行的SQL 如下所示:
可以看到参数化查询主要做了这些事情:
1:参数过滤,可以看到 @UserName='b'' or 1=1—'
2:执行计划重用
因为执行计划被重用,所以可以防止SQL注入。
首先分析SQL注入的本质,
用户写了一段SQL 用来表示查找密码是a的,用户名是b的所有用户的数量。
通过注入SQL,这段SQL现在表示的含义是查找(密码是a的,并且用户名是b的,) 或者1=1 的所有用户的数量。
可以看到SQL的语意发生了改变,为什么发生了改变呢?,因为没有重用以前的执行计划,因为对注入后的SQL语句重新进行了编译,因为重新执行了语法解析。所以要保证SQL语义不变,即我想要表达SQL就是我想表达的意思,不是别的注入后的意思,就应该重用执行计划。
如果不能够重用执行计划,那么就有SQL注入的风险,因为SQL的语意有可能会变化,所表达的查询就可能变化。
在SQL Server 中查询执行计划可以使用下面的脚本:
有篇文章《Sql Server参数化查询之where in和like实现详解》中有这么一段:
这里作者有一句话:”不过这种写法和直接拼SQL执行没啥实质性的区别”
任何拼接SQL的方式都有SQL注入的风险,所以如果没有实质性的区别的话,那么使用exec 动态执行SQL是不能防止SQL注入的。
比如下面的代码:
执行的SQL 如下:
可以看到SQL语句并没有参数化查询。
如果你将UserID设置为”1,2,3,4); delete from U—-”,那么执行的SQL就是下面这样:
exec sp_executesql N'exec(''select * from Users(nolock) where UserID in (&varchar(max) ',@UserID='1,2,3,4); delete from U--'
不要以为加了个@UserID 就代表能够防止SQL注入,实际执行的SQL 如下:
任何动态的执行SQL 都有注入的风险,因为动态意味着不重用执行计划,而如果不重用执行计划的话,那么就基本上无法保证你写的SQL所表示的意思就是你要表达的意思。 这就好像小时候的填空题,查找密码是(____) 并且用户名是(____)的用户。不管你填的是什么&#20540;,我所表达的就是这个意思。 最后再总结一句:因为参数化查询可以重用执行计划,并且如果重用执行计划的话,SQL所要表达的语义就不会变化,所以就可以防止SQL注入,如果不能重用执行计划,就有可能出现SQL注入,存储过程也是一样的道理,因为可以重用执行计划。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:26841次
排名:千里之外
原创:60篇
转载:16篇
(1)(3)(2)(3)(3)(10)(7)(9)(11)(5)(14)(8)您所在的位置: &
参数化查询为什么能够防止SQL注入(1)
参数化查询为什么能够防止SQL注入(1)
任何动态的执行SQL 都有注入的风险,因为动态意味着不重用执行计划,而如果不重用执行计划的话,那么就基本上无法保证你写的SQL所表示的意思就是你要表达的意思。
很多人都知道SQL注入,也知道SQL参数化查询可以防止SQL注入,可为什么能防止注入却并不是很多人都知道的。
本文主要讲述的是这个问题,也许你在部分文章中看到过这块内容,当然了看看也无妨。
首先:我们要了解SQL收到一个指令后所做的事情:
具体细节可以查看文章:Sql Server 编译、重编译与执行计划重用原理
在这里,我简单的表示为: 收到指令 -& 编译SQL生成执行计划 -&选择执行计划 -&执行执行计划。
具体可能有点不一样,但大致的步骤如上所示。
接着我们来分析为什么拼接SQL 字符串会导致SQL注入的风险呢?
首先创建一张表Users:
CREATE&TABLE&[dbo].[Users]( &&[Id]&[uniqueidentifier]&NOT&NULL, &&[UserId]&[int]&NOT&NULL, &&[UserName]&[varchar](50)&NULL, &&[Password]&[varchar](50)&NOT&NULL, &&&CONSTRAINT&[PK_Users]&PRIMARY&KEY&CLUSTERED& &&( &&[Id]&ASC&&)WITH&(PAD_INDEX&&=&OFF,&STATISTICS_NORECOMPUTE&&=&OFF,&IGNORE_DUP_KEY&=&OFF,&ALLOW_ROW_LOCKS&&=&ON,&ALLOW_PAGE_LOCKS&&=&ON)&ON&[PRIMARY] &&)&ON&[PRIMARY]&
插入一些数据:
INSERT&INTO&[Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES&(NEWID(),1,'name1','pwd1'); &INSERT&INTO&[Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES&(NEWID(),2,'name2','pwd2'); &INSERT&INTO&[Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES&(NEWID(),3,'name3','pwd3'); &INSERT&INTO&[Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES&(NEWID(),4,'name4','pwd4'); &INSERT&INTO&[Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES&(NEWID(),5,'name5','pwd5');&
假设我们有个用户登录的页面,代码如下:
验证用户登录的sql 如下:
select&COUNT(*)&from&Users&where&Password&=&'a'&and&UserName&=&'b'&&
这段代码返回Password 和UserName都匹配的用户数量,如果大于1的话,那么就代表用户存在。
本文不讨论SQL 中的密码策略,也不讨论代码规范,主要是讲为什么能够防止SQL注入,请一些同学不要纠结与某些代码,或者和SQL注入无关的主题。
可以看到执行结果:
这个是SQL profile 跟踪的SQL 语句。
注入的代码如下:
select&COUNT(*)&from&Users&where&Password&=&'a'&and&UserName&=&'b'&or&1=1&'&
这里有人将UserName设置为了 &b' or 1=1 &&.
实际执行的SQL就变成了如下:
可以很明显的看到SQL注入成功了。
很多人都知道参数化查询可以避免上面出现的注入问题,比如下面的代码:
class&Program &{ &&&&&private&static&string&connectionString&=&&Data&Source=.;Initial&Catalog=TIntegrated&Security=True&; &&&&&&static&void&Main(string[]&args) &&&&&{ &&&&&&&&&Login(&b&,&&a&); &&&&&&&&&Login(&b'&or&1=1--&,&&a&); &&&&&} &&&&&&private&static&void&Login(string&userName,&string&password) &&&&&{ &&&&&&&&&using&(SqlConnection&conn&=&new&SqlConnection(connectionString)) &&&&&&&&&{ &&&&&&&&&&&&&conn.Open(); &&&&&&&&&&&&&SqlCommand&comm&=&new&SqlCommand(); &&&&&&&&&&&&&comm.Connection&=& &&&&&&&&&&&&&&&&&&&&&&&&&&mandText&=&&select&COUNT(*)&from&Users&where&Password&=&@Password&and&UserName&=&@UserName&; &&&&&&&&&&&&&comm.Parameters.AddRange( &&&&&&&&&&&&&new&SqlParameter[]{&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&new&SqlParameter(&@Password&,&SqlDbType.VarChar)&{&Value&=&password}, &&&&&&&&&&&&&&&&&new&SqlParameter(&@UserName&,&SqlDbType.VarChar)&{&Value&=&userName}, &&&&&&&&&&&&&}); &&&&&&&&&&&&&&comm.ExecuteNonQuery(); &&&&&&&&&} &&&&&} &}&
实际执行的SQL 如下所示:
exec&sp_executesql&N'select&COUNT(*)&from&Users&where&Password&=&@Password&and&UserName&=&@UserName',N'@Password&varchar(1),@UserName&varchar(1)',@Password='a',@UserName='b'&&exec&sp_executesql&N'select&COUNT(*)&from&Users&where&Password&=&@Password&and&UserName&=&@UserName',N'@Password&varchar(1),@UserName&varchar(11)',@Password='a',@UserName='b''&or&1=1&'&
可以看到参数化查询主要做了这些事情:
1:参数过滤,可以看到 @UserName='b'' or 1=1&'
2:执行计划重用
因为执行计划被重用,所以可以防止SQL注入。
首先分析SQL注入的本质,
用户写了一段SQL 用来表示查找密码是a的,用户名是b的所有用户的数量。
通过注入SQL,这段SQL现在表示的含义是查找(密码是a的,并且用户名是b的,) 或者1=1 的所有用户的数量。
可以看到SQL的语意发生了改变,为什么发生了改变呢?,因为没有重用以前的执行计划,因为对注入后的SQL语句重新进行了编译,因为重新执行了语法解析。所以要保证SQL语义不变,即我想要表达SQL就是我想表达的意思,不是别的注入后的意思,就应该重用执行计划。
如果不能够重用执行计划,那么就有SQL注入的风险,因为SQL的语意有可能会变化,所表达的查询就可能变化。
在SQL Server 中查询执行计划可以使用下面的脚本:
DBCC&FreeProccache &&select&total_elapsed_time&/&execution_count&平均时间,total_logical_reads/execution_count&逻辑读, &usecounts&重用次数,SUBSTRING(d.text,&(statement_start_offset/2)&+&1, &&&&&&&&&&((CASE&statement_end_offset& &&&&&&&&&&&WHEN&-1&THEN&DATALENGTH(text) &&&&&&&&&&&ELSE&statement_end_offset&END& &&&&&&&&&&&&&-&statement_start_offset)/2)&+&1)&语句执行&from&sys.dm_exec_cached_plans&a &cross&apply&sys.dm_exec_query_plan(a.plan_handle)&c &,sys.dm_exec_query_stats&b &cross&apply&sys.dm_exec_sql_text(b.sql_handle)&d &&ORDER&BY&total_elapsed_time&/&execution_count&DESC;&
博客园有篇文章:
内容导航&第 1 页: &第 2 页:
关于&&&&的更多文章
随着网络时代的飞速发展,网络安全问题越来越受大家的关注,而SQL
网友评论TOP5
数据库产品
数据库综合
数据库新闻
维基百科将切换到另外一款开源数据库MariaDB
本专题将为大家介绍的MySQL日志的相关操作,日志文件
MySQL内存管理主要是对于缓存的操作管理,涉及到查询
DBA是数据库管理员,英文是Database Administrator。用
Java Web程序员直接在JSP页面中书写Java代码的做法,使得页面中混杂有JavaScript、HTML、Java等多种语言的程序代码,可读性差,
51CTO旗下网站Asp.net(200)
&%@ Page Language=&C#& AutoEventWireup=&true& CodeFile=&LoginTest.aspx.cs& Inherits=&LoginTest& %&
&!DOCTYPE html PUBLIC &-//W3C//DTD XHTML 1.0 Transitional//EN& &http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&&
&html xmlns=&http://www.w3.org/1999/xhtml&&
&head runat=&server&&
&title&参数化提交SQL语句和拼接SQL语句安全性分析 SQL注入 简单对比分析&/title&
&form id=&form1& runat=&server&&
用户名:&asp:TextBox ID=&TextBox1& runat=&server&&&/asp:TextBox&&br /&
密码:&asp:TextBox ID=&TextBox2& runat=&server&&&/asp:TextBox&&br /&
&asp:Button ID=&Button1& runat=&server& Text=&SQL传递参数& OnClick=&Button1_Click& /&&&
&asp:Button ID=&Button2& runat=&server& Text=&SQL拼接语句& OnClick=&Button2_Click& /&
using System.Collections.G
using System.D
using System.Data.SqlC
using System.L
using System.W
using System.Web.UI;
using System.Web.UI.WebC
using MSCL;
public partial class LoginTest : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
//本文仅对 参数化提交SQL语句和拼接SQL语句安全性分析 SQL注入 简单对比分析
//至于各位在程序中 进行SQL危险字符检测和过滤 不在此讨论范围
protected void Button1_Click(object sender, EventArgs e)
string UserName = TextBox1.Text.Trim();
string Pwd = TextBox2.Text.Trim();
//实例化Connection对象
SqlConnection connection = new SqlConnection(&server=database=uid=pwd=smile&);
connection.Open();
//实例化Command对象
SqlCommand command = new SqlCommand(&SELECT COUNT(*) FROM USERINFO WHERE USERNAME=@USERNAME AND UPWD=@UPWD&, connection);
//第一种添加查询参数的例子
SqlParameter para1 = new SqlParameter(&@USERNAME&, SqlDbType.NVarChar, 50);
para1.Value = UserN
command.Parameters.Add(para1);//添加参数
SqlParameter para2 = new SqlParameter(&@UPWD&, SqlDbType.NVarChar, 50);
para2.Value = P
command.Parameters.Add(para2);//添加参数
int i = Convert.ToInt32(command.ExecuteScalar());
if (i & 0)
Response.Write(&成功&);
Response.Write(&失败&);
connection.Close();
SqlParameter[] parameters ={
new SqlParameter(&@USERNAME&,SqlDbType.NVarChar,50),
new SqlParameter(&@UPWD&,SqlDbType.NVarChar,50)};
parameters[0].Value = UserN
parameters[1].Value = P
string sql = &SELECT COUNT(*) FROM USERINFO WHERE USERNAME=@USERNAME AND UPWD=@UPWD&;
int i = Convert.ToInt32(MSCL.SqlHelper.GetSingle(sql, parameters));
if (i & 0)
Response.Write(&成功&);
Response.Write(&失败&);
protected void Button2_Click(object sender, EventArgs e)
string UserName = TextBox1.Text.Trim(); //随便输入
string Pwd = TextBox2.Text.Trim(); //典型SQL登陆注入 输入
a' or '1'='1
object obj = MSCL.SqlHelper.GetSingle(&SELECT COUNT(*) FROM USERINFO WHERE USERNAME='& + UserName + &' AND UPWD='& + Pwd + &' &);
if (Convert.ToInt32(obj) & 0)
Response.Write(&成功&);
Response.Write(&失败&);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1239488次
积分:13090
积分:13090
排名:第727名
原创:232篇
转载:191篇
评论:109条
(2)(12)(10)(4)(2)(7)(38)(2)(1)(1)(1)(1)(7)(12)(7)(3)(4)(6)(6)(5)(13)(6)(4)(9)(6)(14)(6)(17)(6)(6)(5)(5)(18)(6)(19)(9)(19)(18)(41)(16)(22)(27)}

我要回帖

更多关于 sql参数注入 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信