使用LINQ解除SQL注入安全问题
LINQ概述
LINQ增加了用任何类型的数据存储进行查询和更新数据的标准模式,无论是SQL数据库还是XML文档,还是.NET对象都是这样。在构建数据库驱动的应用程序时,LINQ能够使开发人员像管理C#或者VB中的对象那样管理相关数据,这称为“LINQ to SQL”,被看作是ADO.NET数据技术系统的一部分。在最初以CTP形式引入时,LINQ to SQL被认为是DLINQ。
LINQ to SQL使得你将应用程序中的数据作为你所使用的编程语言中的本地对象,简化相关数据管理和数据库连接的复杂性。事实上,你可以通过LINQ显示和操作数据库的数据,而无需你编写任何SQL语句。在运行时刻,LINQ to SQL将嵌入或“集成”到你的代码中的查询转换成SQL,并在数据库系统上执行它们。LINQ to SQL以对象的形式将查询结果返回到应用程序中,完全转移了你与数据库及SQL的交互形式。没有什么清除Web应用程序中的SQL注入的方法能够比从应用程序中清除SQL更快。停靠LINQ to SQL,你就可以实现。
保障LINQ数据库存取的安全
LINQ to SQL在专用于数据存取时,清除了SQL注入存在于你的应用程序中的可能性,原因很简单:LINQ代表你执行的每次查询都加上了具体的参数。在LINQ从你植入的查询语句中构建SQL查询时,无论源自何处,提交给查询的任何输入都被当作字面值。而且,通过IntelliSense和编译时的语法检查,LINQ与Visual Studio Orcas的集成可以帮助开发人员构建合法的查询。编译器可以捕捉大量的对查询的错误使用,这些错误使用可以将功能上的缺陷或其它类型的漏洞带入到你的应用程序中。与此不同的是,在你获知它正确与否之前,你编写的SQL语句只在运行时刻在数据库系统上解析。针对LINQ to SQL的唯一攻击途径是攻击者欺骗LINQ形成非法的或无意识的SQL。幸运的是,语言和编译器就是设计来保护这个方面的。
在清楚了上述的基本思想后,下面我们就展示应该如何运用LINQ to SQL防护SQL注入式攻击,并具体讨论一个客户搜索的例子。第一步是创建数据库中有关数据的对象模型。Visual Studio Orcas包含一个新的对象关系设计器(Object Relational Designer),这个设计器使你能够生成一个完全的对象模型。为了为我们的Northwind Customers表构建一个对象模型,你通过选择“增加新项目…”并选择“LINQ to SQL File”模板(这个模板是在对象关系设计器中打开的),在应用程序中创建一个LINQ to SQL的数据库。为了给 Customers表自动构建完全的对象模型,在服务器资源管理器 (Server Explorer)中选择这个表,并将它拖到对象关系设计器的设计层面上。在这个例子中,对象关系设计器增加了一个名为Customers.designer.cs的文件,这个文件以代码的形式定义了你将要使用的类,而不是编写代码直接与数据库进行交互。
在为Customers表中的数据定义了对象模型的类之后中,你可以为客户的数据搜索页面直接以代码的形式查询数据。LINQ-powered 页面(LINQtoSQL.aspx.cs)的Page_Load方法,具体展现了由对象关系设计器创建的CustomersDataContext类,重新使用了前面在SQLInjection.aspx页面中使用的连接字符串。下面的LINQ查询重新使用了与where子句匹配的Customer对象的集合。
protected void Page_Load(object sender, EventArgs e) { string connectionString = ConfigurationManager.ConnectionStrings ["northwndConnectionString1"].ConnectionString; CustomersDataContext db = new CustomersDataContext(connectionString); GridView1.DataSource = from customer in db.Customers where customer.CompanyName == txtCompanyName.Text orderby customer.CompanyName select customer; GridView1.DataBind(); } |
在使用了LINQ to SQL之后,如果我们将“Ernst Handel”作为搜索值,由LINQ在运行时生成并在服务器上执行的SQL语句看起来将会是如下这个样子:
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE [t0].[CompanyName] = @p0 ORDER BY [t0].[CompanyName]} |
可以看出,WHERE子句自动被加上了参数,因此,用传统的SQL注入式攻击是无法造成破坏的。不管用户将什么值作为输入提交给搜索页面,这个查询是安全的,它不允许用户的输入执行服务器上的命令。如果你输入了前面例子中用来实施SQL注入攻击的字符串,查询并不会返回任何信息。事实上,一个用户用这个查询可以进行的最大的破坏是执行一次强力攻击(或称蛮力攻击(Brute force attack)),主要通过使用搜索功能穷举Customers表中所有公司的记录,其使用的方法是猜测每一个可能的值。不过,即使这样也只提供了那个页面上所暴露的Customers表中的值,并不会给攻击者注入命令的机会,这里的命令指的是访问数据库中额外的数据表的命令。
LINQ与安全
正如前面的例子所显示的那样,在Web应用程序中引入SQL注入漏洞是很容易的,不过采用适当的方法也容易修正这些漏洞。但是,没有什么方法天生就能防止开发人员犯这些简单的但却是危险的错误。然而,微软的LINQ to SQL技术通过让开发人员直接与对象模型交互而不是直接与数据库交互,消除了来自数据库应用程序的SQL注入攻击的可能性。内建于c#和Visual Basic的 LINQ基础结构关注正确地表述合法而安全的SQL语句,可以防止SQL注入攻击,并使开发人员专注于对他们来说最自然的程序设计语言。不管你是将LINQ to SQL用作新的.NET应用程序开发的一部分,还是对它进行花样翻新,用于现有的实际应用程序的数据访问,你都是作了一个构建更安全的应用程序的选择。