随着网络的发展,网络攻击也日趋严重,来自WebCohort的报告显示至少92%的网络应用程序可能受到某种形式的黑客攻击,这些应用程序中60%是有可能遭受SQL 注入攻击的 。由于SQL 注入攻击利用的是SQL 语法,使得这种攻击具有广泛性,理论上讲,对于所有基于SQL 语言标准的数据库都是有效的, 包括MS SQL Server , Oracle , DB2 , Sybase ,MySQL 等,因此给出防止SQL 注入的方案具有积极意义。目前防止SQL 注入的方法能防止已知SQL 注入的发生,但随着新的SQL 注入形式不断出现,现有的防范措施就形同虚设。本文将利用“语言级集成查询(LINQ) ”技术给出一种防止SQL 注入的全新方案。
1 SQL 注入安全漏洞
1. 1 SQL 注入原理
SQL 注入是一种源于SQL 语法漏洞的攻击,攻击者通过构造一个正常使用者意料之外的输入,从数据库获得未经授权的访问,可以达到非法登录、获取密码、下载或删除数据库等各种目的,SQL 注入理论上可以攻击所有使用SQL 语言标准的数据库,具有攻击面广、构造简单、破坏力强等特点。这里我们给出一个SQL 注入的例子来说明SQL 注入攻击:这个示例是一个简单的搜索页面,按产品编号搜索数据表Proudct 中的产品,它动态地完成从用户提供的输入中生成查询。
Copy to Clipboard引用的内容:[www.veryhuo.com]
″SELECT [ ProductID] , [ ProductName ] FROM [ Product ]
WHERE [ ProductID] ="+ txtID. Text +″″;
如果输入产品编号“001”,会显示对应产品的记录,这是期望的理想情况,但攻击者可以轻易地操纵这个动态查询。
例如,攻击者通过插入一个UNION 子句,并用一个注释符号终止这个语句的剩余部分,输入如下的恶意语句:
001′UNION SELECT [UserName ] ,
[UserPassword] FROM [User ] – – ′
现在查询变换为:
Copy to Clipboard引用的内容:[www.veryhuo.com]
SELECT [ ProductID ] , [ ProductName ] FROM [ Product ]
WHERE [ ProductID] =′001′
UNION SELECT [UserName ] ,[UserPassword ] FROM [User ]
– – ′
这是一个相当合法的SQL 语句,在应用程序数据库上执行后就返回User 表中所有用户的用户名和密码,成功地实现SQL 注入。
1. 2 现有解决方案及其存在问题
针对SQL 攻击,前人做过大量的防御工作,目前常用的解决方案如下:
(1) 封装客户端提交信息;
(2) 替换或删除敏感字符/ 字符串;
(3) 屏蔽出错信息;
(4) 在服务端正式处理之前对提交数据的合法性进行检查;
(5) 使用存储过程代替SQL 语句。
方案(1) 的做法需要RDBMS 的支持,不通用;方案(2) 是一种不完全的解决措施,举例来说明他的弱点,当客户端的输入为“ ?aabcbabcc ?”时,在对敏感字符串“abc”替换删除以后,剩下的字符正好是“ ?abc ?”;方案(3) 的实质是在服务端处理完毕之后进行补救,攻击已经发生,只是阻止攻击者知道攻击的结果;方案(4) 被多数的研究者认为是最根本的解决手段,在确认客户端的输入合法之前,服务端拒绝进行关键性的处理操作。方案(4) 与(2) 的区别在于,方案(4) 一旦检测到敏感字符/ 字符串,针对数据库的操作即行中止,而方案(2) 是对有问题的客户端输入做出补救,不中止程序后续操作。这两种方案虽然在一定程度上有效,但只对已知攻击能进行有效检测,而对新发现的攻击方式就不能进行阻止,只要允许服务端程序使用这些提交信息,就总有受到攻击的可能。方案(5) 相对安全些,但存储过程不对嵌入式查询中的SQL 注入提供保护。
2 LINQ 解决SQL 注入方案
微软最新的数据访问技术向. NET 开发人员提供了“语言级集成查询”Language – Integrated Query (LINQ) ,借助LINQ to SQL 技术为. NET开发人员提供了一种可以清除Web 应用程序中的SQL 注入漏洞的方法。它增加了使用任何类型的数据存储进行查询和更新数据的标准模式,将应用程序中的数据作为编程语言中的本地对象看待,简化了相关数据管理和数据库连接的复杂性,事实上,可以通过LINQ 显示和操作数据库的数据,而无需编写任何SQL 语句。在运行时,LINQ to SQL 将嵌入或“集成”到代码中的查询转换成SQL ,并在数据库系统上执行,完全转移了与数据库及SQL 的交互形式,保障LINQ 数据库存取的安全。LINQ to SQL 在用于数据存取时,清除了应用程序中SQL注入的可能性,原因是LINQ 每次执行的查询都加上了具体的参数。在LINQ 从植入的查询语句中构建SQL 查询时,无论源自何处,提交给查询的任何输入都被当作字面值。而且,LINQ 与Visual Studio Orcas 的集成可以帮助开发人员构建合法的查询,编译器可以捕捉到大量的对错误查询,以免这些错误使用将功能上的缺陷或其它类型的漏洞带入到的应用程序中。与此不同的是,在获知它正确与否之前,SQL 语句只能在运行时在数据库系统上解析。唯一攻击途径是攻击者欺骗LINQ 形成针对LINQ to SQL 的非法SQL。幸运的是,语言和编译器可以保护这个方面。在清楚了上述的基本思想后,我们就可以展示应该如何运用LINQ to SQL 防护SQL 注入式攻击。第一步是创建数据库中有关数据的对象模型。Visual Studio Orcas 包含一个新的对象关系设计器(Object Relational Designer) ,这个设计器使能够生成一个完全的对象模型。在前面的SQL 注入攻击示例中由对象关系设计器为Product 表构建一个对象模型Product2DataContext 类文件,这个类文件以代码的形式定义将要使用的类ProductDataContext ,而不是编写代码直接与数据库进行交互。在为Product 表中的数据定义了对象模型的类之后,可以在搜索页面直接以代码的形式查询产品的数据。下面的LINQ 查询重新使用了与where 子句匹配的Product 对象的集合。
Copy to Clipboard引用的内容:[www.veryhuo.com]
{. . .
ProductDataContext db = new
ProductDataContext (connectionString) ;
GridView1. DataSource = from Product in db. Product where
Product. ProductID = = txtProductID. Text
select Product ;
GridView1. DataBind() ;
}
在使用了LINQ to SQL 之后,如果我们将编号“001”作为搜索值,由LINQ 在运行时生成并在服务器上执行的SQL 语句看起来将会是如下这个样子:
view sourceprint?1 SELECT [ t0 ] . [ ProductID ] , [ t0 ] . [ ProductName ] FROM [ dbo ] . [Products ] AS [ t0 ]WHERE [ t0 ] . [ ProductID] = @p0}
可以看出,WHERE子句自动被加上了参数,由参数的特点可知,不允许将用户的输入内容执行服务器上的命令,因
此不管用户将什么值作为输入提交给搜索页面,这个查询都是安全的,如果输入了前面例子中用来实施SQL 注入攻击的字符串,查询并不会返回任何信息,从而实现防御SQL 注入式攻击的作用,使攻击无法造成破坏。
3 总结
根据本文提出的使用LINQ to SQL 防止SQL 注入的新方案,使开发人员直接与对象模型交互而不是直接与数据库交互,可以安全地消除来自数据库应用程序的SQL 注入攻击,使SQL 注入问题得以较好的解决,确保了WEB 应用程序的安全,这个新方案的提出为常见的SQL 关系型数据库提供了安全保障,具有重大现实意义。