如何防止SQL注入?(存储过程,参数化都用到了!)

niunan 2008-11-17 03:39:37
发现存储过程中如果是用到了SQL拼接的话那即使前台使用param参数化的话也会造成SQL注入的!
下面是我存储过程的内容:

-- =============================================
-- Author: 牛腩
-- Create date: 2008-11-17 14:38
-- Description: 添加类别,测试存储过程是否有SQL注入危险
-- =============================================
ALTER PROCEDURE [dbo].[category_insert]
@name varchar(100)
AS
BEGIN
declare @sql varchar(1000)
set @sql = 'insert into category(name) values('''+@name+''')'
exec (@sql)
END

下面是前台ASPX页面的代码片段:

string connStr = @"server=niunan\sqlexpress; database=newssystem; uid=sa; pwd=123456";
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand cmd = new SqlCommand("category_insert", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@name", "bbb');delete category where id=14--"));
int i = cmd.ExecuteNonQuery();
conn.Close();
Response.Write(i);

其中id为14的记录在数据表里是存在的,输出的结果是2,我再查询一下数据库,发现原来id为14的记录没有了,请问我们应该怎么防止这样的SQL注入呢?因为在很多地方用到分页,而分页我都是写在一个分页存储过程里的,而这个分页存储过程又是用SQL拼接而成的,这样子就会有SQL注入的危险了!!!请问应该怎么解决?
...全文
1484 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
wangjtapp 2012-09-05
  • 打赏
  • 举报
回复
看了下回复,楼主的问题没几个看懂的。但实际情况就是这样,即时你在aspx里用上了SqlParameter向存储过程A穿参数,也不意味着就没有注入的风险,关键还要看存储过程怎么写的。正如楼主所说,如果存储过程A是动态拼Sql语句的话,那依然可以被注入。但在Sql2000里的分页,top 不支持变量,还只能用动态sql的方式,为了保证安全,可以参考参数化存储过程.
花子多多 2011-10-12
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 heyang1985 的回复:]
cmd.Parameters.Add(new SqlParameter("@name", "bbb');delete category where id=14--"));

这句改成:cmd.Parameters.Add(new SqlParameter("@name", ("bbb');delete category where id=14--").replace("'","''")));
……
[/Quote]
----------
解决燃眉之急谢谢
xueshaoyu 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 lvtouyayayaya 的回复:]
很奇怪,之前看网上说参数化之后一个'会变成两个',那么最后执行的语句不是相当于insert into category(name) values(''bbb'');delete category where id=14
那个values处应该有语法错吧
[/Quote]

category(name) values('''bbb''');delete category where id=14
是这样的
mastermanager 2010-10-29
  • 打赏
  • 举报
回复
不知道为什么,我测试没有出现异常呢?
lvtouyayayaya 2009-07-16
  • 打赏
  • 举报
回复
很奇怪,之前看网上说参数化之后一个'会变成两个',那么最后执行的语句不是相当于insert into category(name) values(''bbb'');delete category where id=14
那个values处应该有语法错吧
wyp001 2009-03-19
  • 打赏
  • 举报
回复
http://www.jb51.net/article/16935.htm

这篇文章里说
CREATE PROCEDURE dt_GetNews
@newstype int
AS
select * from news where newstype=@newstype
GO

可以注入,还写了个“1;drop table news”

我测试了一下不可以注,但是作者的语气实在是让人佩服

都让我有点怀疑存储过程了,顺便问一下
where newstype=@newstype

where (newstype=@newstype)
有没有区别?
niunan 2008-11-18
  • 打赏
  • 举报
回复
呵呵...本人懒嘛....总想能少写点验证代码就少写点,看来得额外的专门写一个过滤危险字符的过滤类哦....
还是得层层验证啊...
datahandler2 2008-11-18
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 duration1 的回复:]
用Server.HtmlEncode(string s); Server.HtmlDecode(string s);可以在一定程度上提高安全性。
[/Quote]
这个是防止脚本破坏的。兄弟,以后要注意了哦
datahandler2 2008-11-18
  • 打赏
  • 举报
回复
这就是所谓的深度注入。通常是要了解你的SQL写法才有办法的。或经验比较老道才有可能猜的出来。
yoursWTR 2008-11-18
  • 打赏
  • 举报
回复
[Quote=引用楼主 niunan 的帖子:]
发现存储过程中如果是用到了SQL拼接的话那即使前台使用param参数化的话也会造成SQL注入的!
[/Quote]

别说你发现了什么了,你东西都搞错了,

SqlParameters提供2种验证,值类型验证和长度验证

在c#下拼接的T-SQL字符串
例如诸如此类

DBHelper.ExecuteNonQuery(
//CommandText
"SELECT TOP 1 * FROM Error WHERE title = @title",
CommandType.Text,
//SqlParameter
DBHelper.CreateSqlParameter(
//映射名
"@title",
//值类型
SqlDbType.NVarChar,
//长度
100,
//传值方式
ParameterDirection.Input,
//值
"'输入字符串的格式不正确。';DELETE FROM Error WHERE eid = 1465 --"
)
);




//值类型
SqlDbType.NVarChar,
//长度
100,


下,值"'输入字符串的格式不正确。';DELETE FROM Error WHERE eid = 1465 --"会被认为是一个长度小于或等于nvrchar(100)的nvrchar类型,而不是T-SQL语句传入CommandText中和拼接完全是2个概念


但是你使用存储过程就表示你的SqlParameters只能提供长度验证(虽然这个说法不是很准确,应该是SqlParameters的值验证起了作用但是传到存储过程后验证就失效了),而你的代码里却没有设置SqlParameters的长度(也没规定SqlParameters值类型),也就是说你的SqlParameters验证是多余的,只起到了个传值的作用,

既然你SqlParameters验证在存储工程里不能起到验证作用,而你的存储过程又是拼接字符串,那你就该做防护措施,多层验证正是微软推荐的方式,不要信任上一层验证,但是你也没做,你怎么不被注入
duration1 2008-11-17
  • 打赏
  • 举报
回复
用Server.HtmlEncode(string s); Server.HtmlDecode(string s);可以在一定程度上提高安全性。
bolome 2008-11-17
  • 打赏
  • 举报
回复
学习!
brio8425 2008-11-17
  • 打赏
  • 举报
回复
支持sp_executesql
mail_ricklee 2008-11-17
  • 打赏
  • 举报
回复

ALTER PROCEDURE [dbo].[category_insert]
@name varchar(100)
AS
BEGIN
declare @sql varchar(1000)
insert into category(name) values(@name);
END

.....

你的代码为什么在里面来一个
exec...
criedshy 2008-11-17
  • 打赏
  • 举报
回复
 if (this.txtUserCode.Text.Contains("'") || this.txtUserCode.Text.Contains("--"))
{
Alert("登陆失败: " + "你的输入含有非法字符,请重新输入");
return;
}
criedshy 2008-11-17
  • 打赏
  • 举报
回复
 if (this.txtUserCode.Text.Contains("'") || this.txtUserCode.Text.Contains("--"))
{
Alert("登陆失败: " + "你的输入含有非法字符,请重新输入");
return;
}
jiezi316 2008-11-17
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 comszsoft 的回复:]
exec 可以改用 sp_executesql
[/Quote]
UP
szh3210 2008-11-17
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 nihaimeiyoudenglu 的回复:]
你这程形式没必要拼啊

ALTER PROCEDURE [dbo].[category_insert]
@name varchar(100)
AS
into category(name) values(@name)

拼字符的话,在前台直接运行sql是一样的效率的啊
[/Quote]

同意

这样注不进去
  • 打赏
  • 举报
回复
如果在存储过程中拼字符串就应该使用t-sql的replace函数替换单引号,在c#的就应该使用c#的replace方法,拼写sql语句时这个不能忽略。
niunan 2008-11-17
  • 打赏
  • 举报
回复
其实在代码执行ExecuteNonQuery()的之前是想过先把传入的参数中的字符都过滤掉的,只是想试试用C#过滤危险参数的代码能不能转到存储过程中,就是把参数全都传到存储过程中后再进行过滤的,总以为只要是在存储过程里的就意为着效率快哪么一点点...呵呵....
试了一下sp_executesql,蛮好用的...以后的存储过程分页就用这招行了..呵呵...
加载更多回复(17)

62,041

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧