以前和大家一样,听人说用存储过程+参数能防止SQL注入,听的多了,也就深信不疑,
就算不是绝对的,至少也有很强大的防御力吧。很多人说自从用了参数+存储,不必过滤字符了,腰也不痛了。今天仔细想了想,在“代码中用变量拼接组合SQL命令”的确危险,有漏洞。
但“存储过程+参数”实质不是一样的吗,虽然传递过程两者有区别,一个是传递组合好的SQL命令字符串,
一个是传递 "存储过程名+参数",不过到了数据库,在存储过程的代码中,最终不是还要将这些参数组合拼接成
一段SQL命令吗?
就好比一个炸弹,一种方法是直接把成品运到某处,另一个是把炸弹的各零件运到某处,某处再拼合,最终还是炸弹譬如:
string myname="a' or 1=1";
在代码中拼接SQL命令:
mysql="select * from table where name='"+myname+"'";
即mysql= "select * from table where name='a' or 1=1";如果我们用参数+存储的方式:
@p1="a' or 1=1"
set @sql="select * from table where name='"+[@p1]+"'"
exec(@sql)
这样exec(@sql)难道不等效于 exec (select * from table where name='a' or 1=1) 吗?
如果是,那和在代码中组合SQL命令有何区别?搜了一下资料,说参数+存储安全性高的大有人在,但认为参数+存储在安全性上并没多大意义的人也不少
,他们认为仍需要进行严格的字符过滤。大家上网搜一下就能看到了。实在是很困惑,请大家各持己见。谢谢。尽量不要用“可以,因为参数是传值”或"你不了解参数的意义"等空洞的回答,再次感谢。
就算不是绝对的,至少也有很强大的防御力吧。很多人说自从用了参数+存储,不必过滤字符了,腰也不痛了。今天仔细想了想,在“代码中用变量拼接组合SQL命令”的确危险,有漏洞。
但“存储过程+参数”实质不是一样的吗,虽然传递过程两者有区别,一个是传递组合好的SQL命令字符串,
一个是传递 "存储过程名+参数",不过到了数据库,在存储过程的代码中,最终不是还要将这些参数组合拼接成
一段SQL命令吗?
就好比一个炸弹,一种方法是直接把成品运到某处,另一个是把炸弹的各零件运到某处,某处再拼合,最终还是炸弹譬如:
string myname="a' or 1=1";
在代码中拼接SQL命令:
mysql="select * from table where name='"+myname+"'";
即mysql= "select * from table where name='a' or 1=1";如果我们用参数+存储的方式:
@p1="a' or 1=1"
set @sql="select * from table where name='"+[@p1]+"'"
exec(@sql)
这样exec(@sql)难道不等效于 exec (select * from table where name='a' or 1=1) 吗?
如果是,那和在代码中组合SQL命令有何区别?搜了一下资料,说参数+存储安全性高的大有人在,但认为参数+存储在安全性上并没多大意义的人也不少
,他们认为仍需要进行严格的字符过滤。大家上网搜一下就能看到了。实在是很困惑,请大家各持己见。谢谢。尽量不要用“可以,因为参数是传值”或"你不了解参数的意义"等空洞的回答,再次感谢。
解决方案 »
- 如梦请进!!!高手请进!!!几天还没有搞定,郁闷
- 非MSIE浏览器弹出窗口,如何屏蔽工具菜单栏等?
- 高分求救:Cookies.值怎么清除不了
- 新闻系统中的 组图 如何实现?
- DataList分页的问题(数据库为Access,存储过程不行了吧)
- gif图片压缩问题
- 各位高手帮忙呀,问题很急的,谁有winform里的DataGrid的增删改的例子,给一个,顶者有分
- 做抓取网页程序遇到的问题,50分寻求帮助
- 个位高手请教你们:appliction\session\cookie这三个是怎样用呢?
- 如何把datagrid中的一列的日期显示格式变为dd/MMM/yyyy(14/Mar/1998)
- 用代码操作文件或文件夹后,Session值被清空了?
- 那位能帮我找个用C#.net和access写的招聘网站的源码程序
据说,使用参数是MSDN推荐的.
http://topic.csdn.net/t/20041220/19/3661597.html
http://www.sudu.cn/info/html/edu/20070526/147386.htmlhttp://k.pconline.com.cn/question/162381.html
http://www.qnr.cn/pc/dj/sanji/shuju/fuxi/200901/115755.html不管怎么样,asp.net代码中给定的SQL的查询或其它操作,最终需要交给SQL数据库内部来处理吧。
就以我贴子中的列子来讲:
如果在代码页中,得到变量str="a' or 1=1"
将变量Str通过SqlParameters 的@p1参数传给SQL服务器,SQL收到的@p1参数值还是不是"a' or 1=1"?
如果是,那么存储过程最终将执行
@sql="select * from table where name='"+[@p1]+"'"
上面这句执行后将会出现什么结果?
存储过程如果使用未筛选的输入,容易受攻击。
使用存储过程,则应使用参数Parameter作为存储过程的输入
测试输入的大小和数据类型,强制执行适当的限制。。
测试字符串变量的内容,只接受所需的值。
绝不直接使用用户输入内容来生成 Transact-SQL 语句。
使用存储过程来验证用户输入。
在多层环境中,所有数据都应该在验证之后才允许进入可信区域。
实现多层验证。
“参数Parameter”(甚至有人说用了参数Parameter,用不用存储都无所谓了),
不过,既然要执行某个需要参数的存储过程,如果不用“Parameter”,还有哪种方式能传递参数呢?是不是像这种:
With mycmd
.ActiveConnection = conn
.CommandType = 4
.CommandText = "oneSP" //存储名
End With
mycmd.Execute ,array(name) //name为参数如果用Parameter,它发挥作用的关键在哪里呢?难道只是“限制了输入变量的长度与数据类型”这一点点作用?
declare @sql varchar(1000)
set @p1="a';select 123 -- or 1=1"
set @sql="select * from sysobjects where name='"+@p1+"'"
exec(@sql)
go
这里,原本是要在变量@p1中保存待查找的name的值,结果有效地执行了 “select 123”这个命令。可以执行更加复杂的命令,例如通过SQL Server的xp_cmdshell过程执行DOS命令,或者使用一条update来更改数据。这表明只要是这种“拼接SQL语句”就是祸根。存储过程中如果有程序员写出这种代码,也一样会被注入。
declare @sql varchar(1000)
set @p1="a';select 123 --"
set @sql="select * from sysobjects where name='"+@p1+"' and id=-103"
exec(@sql)
go
declare @sql varchar(1000)
set @p1="a';select 123 --"
set @sql="select * from sysobjects where name='"+replace(@p1,"'","''")+"' and id=-103"
exec(@sql)
go
人家SQL Server语法明明说必须把字符串常量中的单引号替换为双引号,那么你写"set @sql ...."这行代码的程序员如果你没有足够详细的分析和设计文档记载着@p1绝对不能有单引号,你就应该不管@p1中有没有单引号都要从语法正确角度出发去使用replace函数先对变量值进行处理。这纯粹是一个SQL Server语法懂与不懂的问题,被夸大到SQL注入问题上来,变得非常可笑。我们就要重写这样的SQL代码,跟程序员追问:你写的这段代码就应该能够处理包括单引号的变量,不要拿“过滤单引号”做借口,那是界面开发的事,架构师想过滤什么字符就可以在界面那里配置过滤什么字符,跟你写数据库查询没有关系。当不小心把数值定义到字符串变量中,我们可以写:declare @p1 varchar(1000)
declare @sql varchar(1000)
declare @id varchar(20)
set @p1="a';select 123 --"
set @id="-102"
set @sql="select * from sysobjects where name='"+replace(@p1,"'","''")+"' and id="+
cast(cast(@id as int) as varchar)
exec(@sql)
go
使用两个cast首先验证@id确实是一个int,然后再重新生成字符串,最后才拼接到SQL。
存储过程+参数不是万能的.但相对于你的拼接SQL是要安全的很多..
倒是 参数可以过滤SQL注入。
但是传参不是这么拼凑sql啊cmd.Parameters.Add("@Tags", System.Data.SqlDbType.NVarChar, 255).Value = xxx;
实际上类似这样的都可以过滤,'被替换成''等等..
不过不要以为这样就安全了 create proc xxxx
...
@SearchSQL NText,
....
AS
....Insert into #IDs(PhotoID) exec(@SearchSQL)
像这种参数,在存储过程中执行sql,可以被注入..不信试试
@p1="a' or 1=1"
set @sql="select * from table where name='"+[@p1]+"'"
exec(@sql)
正确的方法应该是
sql = "select * from table where name=@name"
cmd.Parameters("@name" ........)如果是用存储过程,应该在存储过程里面执行 select * from table where name=@name
而不是exec(@sql),这样和普通拼接sql没有什么区别实际应用根据要求来定,比如模糊搜索功能,用LIKE '%words%',这种时候应该进行安全过滤
如果对你来说参数传递 ,只有拼sql 一条路的话,无语了。像你这样 如果查询的是篇 有关sql 的论文 ,里面有很多 sql 关键字 ,估计 楼主 要过滤字符串是 要头疼了吧。
参数+存储过程个人理解为:
数据库里的存储过程应该写成:
Create Proc Procedure_Name
@Param1
As
Begion
select * from table where column1=@Param1
End
使用时给参数赋值即可,而非:
@p1="a' or 1=1"
set @sql="select * from table where name='"+[@p1]+"'"
exec(@sql)
如果这也算漏洞,你怎么不把sa的密码置为空?
谢谢
{
return matchString == null || matchString.Length == 0 ? matchString : ((new Regex(@"(\[|\]|\*|_|%)")).Replace(matchString, "[$1]").Replace("'", "''"));
}传的like key参数经过toSqlLike格式化后,
select * from TABLE where KEY like '%'+@key+'%'
SqlCommand command = conn.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "select * from tab_Test where NId=@id";
SqlParameter param = new SqlParameter("@id", SqlDbType.NVarChar, 50);
param.Value = TextBox1.Text;
command.Parameters.Add(param);TextBox1赋值 1 最终执行的SQL语句是
exec sp_executesql N'select * from tab_Test where NId=@id',N'@id nvarchar(50)',@id=N'1'TextBox1赋值 "a' or 1=1" 最终执行的SQL语句是
exec sp_executesql N'select * from tab_Test where NId=@id',N'@id nvarchar(50)',@id=N'"a'' or 1=1"'
select * from table where column1=@Param1
End
这样是不是就使param1只能当作一个值来处理,而不是成了执行代码的一部分?
不知对于参数,写成name=@name而不加两侧单引号会不会报错。
就像你写一个函数的参数一个,参数里面包含引号,赋值过去难道会出错吗?
如果对于数值类的参数,当然处理很简单了.最麻烦的就是字符串上.至于转换成二进制码的SQL注入倒是没听说过,好象有转换成ascII码的,至于如何防范没见到相关资料.
不过个人分析了一下,发现这种转换后往往会带有%字符,如果将%进行转换或过滤,可能会有一定作用.
set @sql="select * from table where name='"+[@p1]+"'"
exec(@sql) 你这样能建立存储过程吗,语法都不对。你试过了吗还有说不拼接sql,不拼接,能形成完整的sql语句用参数,只能说MS给我们做了一些过滤,SqlParameter规定了你传参数的大小类型
严格过滤还得你自己来
这只是一个例子,你不妨试试下面这代码declare @p1 varchar(1000)
declare @sql varchar(1000)
set @p1='a' + char(39) + ';select 123 --'
set @sql='select * from sysobjects where name='''+@p1+''' and id=-103'
exec(@sql)
go
或者是这样
declare @p1 varchar(1000)
declare @sql varchar(1000)
set @p1=''' + char(39) + '''';select 123 --'
set @sql='select * from sysobjects where name='''+@p1+''' and id=-103'
exec(@sql)
go
但如果将单引号Replace为两个单引号,那就不会出现查询出123的结果了declare @p1 varchar(1000)
declare @sql varchar(1000)
set @p1=''''' + char(39) + '''''''';select 123 --'
set @sql='select * from sysobjects where name='''+@p1+''' and id=-103'
exec(@sql)
go
所以,严格说来,存储过程不会去防止,防止注入的东西就是SqlParameter
declare @p1 varchar(1000)
declare @sql varchar(1000)
set @p1=''''';select 123 --'
set @sql='select * from sysobjects where name='+@p1+' and id=-103'print @sql
exec(@sql)
go
唉,万恶之源还是这种拼接SQL语句的方式将@p1里面的一个单引号替换为两个单引号,还是会出现123
declare @p1 varchar(1000)
declare @sql varchar(1000)
set @p1=''''''''';select 123 --'
set @sql='select * from sysobjects where name='+@p1+' and id=-103'print @sql
exec(@sql)
go
但这没有实质的参数化,还是拼接字符串,真正的参数化是直接:
select * from table where name=@p1