當作為SQL語句的一部分執行時,參數化查詢將輸入作為一個字面值,因此服務器就可能將帶參數的輸入作為可執行代碼。即使你使用了存儲過程,你仍然必須采取另外一步來確定輸入的參數,因為存儲過程并不對嵌入式查詢中的SQL注入提供保護。 即使采取這上述的簡單修正措施,SQL注入對許多公司來說仍然是一個大問題。對開發團隊的挑戰是要教育每一個開發人員謹慎對待這些類型的漏洞,采取有目的的和有效的安全標準來防止攻擊,增強標準和操作安全的評估, 確認無任何疏漏。這樣就會需要引入許多變量去保證應用程序安全,因此如果你選擇一項能夠使SQL注入式攻擊成為不可能的數據訪問技術,你的效率將會更高。這正是LINQ發揮作用之所在。 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 = newCustomersDataContext(connectionString);GridView1.DataSource =from customer in db.Customerswhere customer.CompanyName ==txtCompanyName.Textorderby customer.CompanyNameselect 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] = @p0ORDER 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應用程序開發的一部分,還是對它進行花樣翻新,用于現有的實際應用程序的數據訪問,你都是作了一個構建更安全的應用程序的選擇。