欢迎进入HappyQQ的Blog

成功者找方法,失败者找借口。
随笔 - 171, 文章 - 49, 评论 - 141, 引用 - 3
数据加载中……

软件宝宝系列——SQL注入篇

今天,我给大家介绍的是软件宝宝如何防止SQL注入。
软件宝宝安全成长史系列的第二点:
“2、教会“软件宝宝”什么是好人,什么是坏人,什么东西可以吃,什么东西不能够吃!”
接下来,我们看看软件宝宝在未学会第二点之前所存在的危险,大家看了以后,一定要记得看看自己的软件宝宝是不是也存在这种威胁了?
public void UnsafeQuery (string name)
{
IDbConnection dbConnection = new SqlConnection ();
dbConnection.Open ();
IDbCommand dbCommand = dbConnection.CreateCommand ();
dbCommand.CommandText = "SELECT name, bank_account FROM customers WHERE name = '" + name + "'";
IDataReader dataReader = dbCommand.ExecuteReader ();
PrintAllValuesInReader (dataReader);
dataReader.Close ();
dbCommand.Dispose ();
dbConnection.Close ();
}
上面的代码,大家看出问题了吧,还没看出,打PP了。
假设我们的程序当中正在使用UnsafeQuery (txtInput.text.trim);
当我们在txtInput.text文本框中,我们给宝宝喂点“HappyQQ';drop table customers;--“
宝宝自从吃了这个东西以后,就生病了!
所以说,我们一定要教会软件宝宝什么东西该吃,什么不该吃?
好了,接下来,我们就教教软件宝宝什么东西能吃,什么不能够吃。
告诉宝宝第一种方法:(不能够吃的,全部都不吃)
 private string FormatRemoveSQL( string strSQL )
{
string strCleanSQL = strSQL;

if( strSQL != null )
{
Array BadCommands = ";,--,create,drop,select,insert,delete,update,union,sp_,xp_".Split( ',' );
//数组中保存了哪些是宝宝不能够吃的东西,这下可安全喽!

int intCommand;
for( intCommand = 0; intCommand <= BadCommands.Length - 1; intCommand++ )
{
strCleanSQL = Regex.Replace( strCleanSQL, Convert.ToString( BadCommands.GetValue( intCommand ) ), " ", RegexOptions.IgnoreCase );
}

strCleanSQL = strCleanSQL.Replace( "'", "''" );
}

return strCleanSQL;
}
好了,接下来,我们用UnsafeQuery (FormatRemoveSQL(txtInput.text.trim));
软件宝宝以后就不会再吃这个坏东西了!(SQL注入)
告诉软件宝宝,第二种方法,坏东西不要吃,但是还是可以看看的嘛!

public void SafeQuery (string name)
{
IDbConnection dbConnection = new SqlConnection ();
dbConnection.Open ();
IDbCommand dbCommand = dbConnection.CreateCommand ();
dbCommand.CommandText = "SELECT name, bank_account FROM customers WHERE name = @name";
dbCommand.Parameters.Add (new SqlParameter ("@name", DbType.String).Value = name);
IDataReader dataReader = dbCommand.ExecuteReader ();
PrintAllValuesInReader (dataReader);
dataReader.Close ();
dbCommand.Dispose ();
dbConnection.Close ();
}
当我们的程序中使用safeQuery (txtInput.text.trim);
 
最后总结:对付SQL注入,我们可以过滤其危险字符,或者采用参数化传值方式都可以。(文章中所介绍的方法同样可以应用到XSS漏洞的防护)

作者:黄启清

日期:2008-7-3

同时,谨以此文献给我最亲爱的妈妈(http://mama520.cn)

CNBLOGS安全团队欢迎您的加入!
 
成功者找方法,失败者找借口!

posted on 2008-07-03 23:24 HappyQQ 阅读(1872) 评论(21)  编辑 收藏 所属分类: 编程技术 网络安全

评论

#1楼    回复  引用    

什么是mdash。*

#2楼    回复  引用  查看    

过滤危险字符的方式相当麻烦,远不如第二种参数化传值方式可靠。
2008-07-04 00:49 | Angel Lucifer      

#3楼    回复  引用  查看    

使用参数并不能完全防止SQL Injection,使用特殊字符串过滤如果实际业务中真需要传入这些字符串怎么办?
2008-07-04 01:14 | 深蓝      

#4楼    回复  引用  查看    

不是一个很好的方法。
2008-07-04 08:08 | ★金★      

#5楼    回复  引用  查看    

对于SQL注入的预防应该再往前推进一步,即放到业务外观处,而不是等查询真的被执行的时候。所有的请求都是不可信的,但是我们应该相信我们的数据访问层。
另外采用一个模块来对请求进行安全检查要比楼主这样写好的多。

2008-07-04 08:34 | 布尔      

#6楼    回复  引用  查看    

@深蓝
---------------------------------------------------------------
使用参数并不能完全防止SQL Inj
ection,使用特殊字符串过滤如果实际业务中真需要传入这些字符串怎么办?
---------------------------------------------------------------

这个观点,我不太同意,请问可不可以举出例子呢
谢谢
2008-07-04 08:35 | killkill      

#7楼 [楼主]   回复  引用  查看    

我举这个例子只是说明如何防止SQL注入
TO 布尔 :
并未关系到什么系统架构的应用,感谢所有朋友的建议。
TO 深蓝 :
是的,所有一切的输入都有可能是有害的。
2008-07-04 09:29 | HappyQQ      

#8楼    回复  引用  查看    

@killkill
比如你做国外项目啊,create,drop,select,insert,delete,update,这些都是老外用的基本词汇啊,凭什么不让人家用。
2008-07-04 10:23 | kiler      

#9楼    回复  引用  查看    

...
1.过滤是不可取的方式
2.参数化传递可以避免SQL Injection,而且即使在参数中有SQL Injection的格式,一样可以被正确地插到数据库中. 原则上来说,所有的Connector都应该provide一个encode参数的功能,如果说使用了参数方式还是会有SQL Injection的情况发生,那这个Connector一定是第三方公司出品的劣质Connector

2008-07-04 11:06 | Klesh Wong      

#10楼    回复  引用  查看    

用特殊字符串过滤如果实际业务中真需要传入这些字符串怎么办?

假设实际的业务数据中包含有',那按你这样的话就会过滤掉,根本就搜索不到结果,这样的做法不妥,过滤效率也不是很好
2008-07-04 11:53 | jowo      

#11楼    回复  引用  查看    

我们现在客户端过滤一下,后台再用存储过程传递参数。

2008-07-04 11:54 | 朝晖的.net      

#12楼 [楼主]   回复  引用  查看    

感谢所有朋友的支持与建议

我上面已经建议两种方式,到底采用哪种方式,就要根据自己的项目而定。

不过我的建议是,安全方面,越严越好
2008-07-04 12:02 | HappyQQ      

#13楼    回复  引用  查看    

@kiler
我不同意的是:
“用参数不能避免SQL 注入”
这个命题

不是反对原著作者的观点
2008-07-04 13:22 | killkill      

#14楼    回复  引用  查看    

@HappyQQ
第一种方式完全不可取
第二种才是正规的方式,不会有SQL 注入问题.
2008-07-04 14:07 | Klesh Wong      

#15楼    回复  引用  查看    

@深蓝
使用参数并不能完全防止SQL Injection
-------------------------------------
举个例子
在存储过程中还拼SQL的不用说了
2008-07-04 15:04 | jillzhang      

#16楼    回复  引用  查看    

据我所知,你这个只是sql中的比较常用的一种,现实很复杂,建议最好用参数。
2008-07-04 15:08 | jillzhang      

#17楼    回复  引用  查看    

参数化是能避免sql注入问题的,如果楼主不同意,你可以尝试注入一下,看你能否攻破。

另说一下,参数化还要保证动态执行sql的时候,需要sp_executesql,不然也不算是参数化。
2008-07-04 16:14 | PerfectDesign      

#18楼    回复  引用  查看    

--引用--------------------------------------------------
jillzhang: @深蓝
使用参数并不能完全防止SQL Injection
-------------------------------------
举个例子
在存储过程中还拼SQL的不用说了
--------------------------------------------------------

有道理,不过在存储过程中还拼装SQL也是很不好的做法.应该尽量避免.
2008-07-04 16:38 | Klesh Wong      

#19楼    回复  引用  查看    

根据我的经验杜绝注入的最有效方式就是参数强类型化并且对字符串中的单引号进行替换足矣。而这些用ORM等完全可以做到。
2008-07-04 21:57 | Edward.Net      

#20楼    回复  引用  查看    

@jillzhang
正如你所说的,就是动态执行SQL语句这种情况,虽然在项目中应该尽量避免,但是在某些特殊的情况下(比如高级搜索)选择使用动态SQL会更快。
2008-07-04 22:26 | 深蓝      

#21楼    回复  引用  查看    

@深蓝
动态表名就会使用动态sql
2008-07-04 23:06 | PerfectDesign