在C#3.0中使用LINQ輕松防御SQL注入攻擊

發表于:2008-05-04來源:作者:點擊數: 標簽:sqlSQL防御LINQ攻擊
隨著Internet逐漸普及,基于Web的各種非法攻擊也不斷涌現和升級,因此,很多 開發 人員被要求使他們的程序變得更 安全 可靠,這也逐漸成為這些開發人員共同面對的問題和責任。而很多使用Web系統的企業也不斷投入大量的資金,以購買和使用更安全的框架和 軟件
 隨著Internet逐漸普及,基于Web的各種非法攻擊也不斷涌現和升級,因此,很多開發人員被要求使他們的程序變得更安全可靠,這也逐漸成為這些開發人員共同面對的問題和責任。而很多使用Web系統的企業也不斷投入大量的資金,以購買和使用更安全的框架和軟件平臺。很多開發人員也從一開始設計程序時就注重使用更有效的方法來建立安全的應用程序,并防止有破壞性的攻擊。但不幸的是,開發團隊的成員經常缺乏這方面的訓練,以及進行安全設計的相關經驗。

    當開發人員為應用程序加入更多的安全防護罩時,也許最先考慮的Web應用程序攻擊就是我們眾所周知的SQL注入攻擊。這是一種通過命令注入方式進行攻擊的方式。命令注入是任何通過在服務端運行非授權程序進行攻擊的基本方法。這種方法一般是通過在客戶端輸入特殊或不可預料的字符串(在字符串中包含有破壞性的命令)來改變Web程序被期望的運行結果。由于這種攻擊方式非常普遍,也非常容易掌握,因此,SQL注入攻擊被大范圍地使用,所以它是非常危險的,甚至是防不勝防的。但幸運的是,如果我們理解了SQL注入攻擊的原理,是很容易防御的。隨著微軟的.NET技術的不斷發展,也為開發人員提供了新的數據接口,如果適當使用它們,就可以完全防止SQL注入攻擊。這項技術被稱為集成查詢語言,也就是LINQ(將在本文的后面進行講解)。這項技術將和即將發布的Visual Studio2008以及.NET Framework 3.5一起發布。本文將帶領讀者探索如何利用LINQ來防止Web程序的SQL注入攻擊,讀者將會從本文深刻體會到LINQ在這方面的無限潛力。

一、什么是SQL注入

    SQL注入是一種對Web應用程序進行的攻擊,黑客通過向應用程序傳遞惡意數據,并欺騙服務器將其當成正確的命令并執行。雖然這種攻擊方法非常容易防御,但它也是非常普遍和有害的。這是因為它可以允許攻擊者直接運行命令來操作我們的工作數據。在很多極端的情況下,攻擊者不僅僅可以訪問我們所有的數據,而且還可以刪除表和數據庫。甚至可以得到控制數據庫服務器的權利。


    既然這些攻擊如此容易防御,那么它們為什么如此危險呢?首先,我們的應用數據庫是一個非常吸引人的蛋糕,原因很簡單,因為在數據庫中保存了很多黑客非常關心的數據。如果SQL注入成功后,攻擊者是非常容易通過這種方式檢測并瀏覽到這些數據的。雖然SQL注入錯誤并不是開發人員最容易犯的錯誤,但它可能卻是攻擊者最常使用,也是最容易成功的攻擊方式。

   
檢查SQL注入攻擊最容易的方法就是在應用程序中可以訪問數據庫的表達式處插入一個元字符串。如一般網站都會包含一個search輸入字段,如果一個攻擊者輸入一個數據庫元字符,如一個"'"符號,如果應用程序反回一個數據庫錯誤信息,攻擊者不僅可以知道他已經發現了這個應用程序的數據庫信息的一部分,而且他可以向其注入更多有意義的命令,并使服務器執行它們。應用程序安全專家Michael Sutton最近使用Google Search API在數分鐘之內發現了數以百記的易受SQL注入攻擊的網站。

二、SQL注入攻擊剖析

   
在本節中將給出個簡單的SQL注入的例子,通過這個例子讀者可以了解了這個錯誤是多么容易犯,并且這些注入錯誤使用一些設計技巧和編程規范就可以很容易地避免。

   
在這個例子中,Web應用程序包含了一個簡單的customer數據查詢頁SQLInjection.aspx。這個頁布在一個非常易受SQL注入攻擊的隱患。這個頁包含了一個CompanyName輸入服務端控件和一個數據網格控件,用來演示從微軟的例子數據庫Northwind查出來的結果(在本例中將使用微軟SQL Server2005作為我們的演示數據庫)。這個查詢在執行時包含了一個非常普遍應用程序設計錯誤,也就是它根據用戶的輸入動態地建立一個SQL查詢語句。這種方式對于Web應用程序訪問數據庫是非常不好的習慣。這是因為這樣做必須有一個前提,就是使用這個Web程序的用戶是可信賴的,如果用戶懷有惡意,那將是非常危險的。下面是Search按鈕中的生成SQL語句的代碼:

protected void btnSearch_Click(object sender, EventArgs e) { String cmd = "SELECT [CustomerID], [CompanyName], [ContactName] FROM [Customers] WHERE CompanyName ='" + txtCompanyName.Text + "'"; SqlDataSource1.SelectCommand = cmd; GridView1.Visible = true; }
在這種情況下,如果一個用戶輸入"Oracle"作為公司名,并單擊Search按鈕,這樣將在瀏覽器中顯示顯示和公司相符的正確的結果。但一個攻擊者也可以很容易地控制動態查詢語句的生成,如,通過插入UNION子句和并通過SQL的注釋符號(--)來終止其余的語句。換句話說,就是使用以下的輸入來代替"Oracle"作為公司名:

Oracle' UNION SELECT CustomerID, ShipName, ShipAddress

   FROM ORDERS--

   
上面SQL表達式在服務端的執行結果是向SQL語句中插入了一條惡意的請求命令。如果將其翻譯成動態的SQL語句的話,代碼如下:


SELECT [CustomerID], [CompanyName], [ContactName] FROM [Customers] WHERE CompanyName ='Oracle' UNION SELECT CustomerID, ShipName, ShipAddress FROM ORDERS--'
    上面所得到的SQL語句的語法完全正確,它將返回Customer表中Oracle的數據,同時也返回了Orders表中所有的數據。顯示結果如圖1如示
 圖一個成功的SQL注入的顯示結果。它通過在命令行后加入非法的命令來獲取數據庫中敏感的信息。
三、典型的SQL安全防護

    到現在為止我們已經看到在應用程序中開始一個SQL注入攻擊并成功使用它是多么的容易。幸運的是,在上面已經提及過,SQL注入攻擊很容易使用一些簡單的手段防御。大多數有效的防御方法是在執行SQL語句之前驗證應用程序中所有的被使用于數據訪問的輸入語句。我們可以在Web應用程序中直接來驗證,也可以使用一些數據持久化組件,如Hibernate進行驗證,當然,不管使用哪種方式,這種驗證都需要在處理數據之前在服務端來驗證類型、長度、格式和范圍。但不幸的是,基于代碼的驗證方法并不十分簡單,當遇到如下三種情況時,還會失?。?BR>
1. 驗證程序設計不完善。

2. 驗證只在客戶端執行。

3. 驗證失敗,即使在應用程序中只有一個單獨的字段。

    還有別外一種防止SQL注入攻擊的方法,就是在應用程序中參數化所有的SQL查詢,無論是動態的SQL表達式,或存儲過程。如果寫出象下面的代碼應該是很安全的:

SELECT [CustomerID], [CompanyName], [ContactName]
   FROM [Customers]
   WHERE CompanyName = @CompanyName
   
參數化的查詢當執行SQL表達式時將輸入看到是一個字符串值;因此,將這個值作為可執行的代碼是不可能的。即使我們使用存儲過程,也必須使用參數化輸入,這是因為存儲過程并不提供使內嵌查詢防止SQL注入的功能。


   
即便使用上述簡單的防護措施,SQL注入仍然會成為許多組織的大問題。對于我們的開發團隊來說,最大的挑戰就是對所有的開發人員進行防御這種攻擊的培訓。甚至需要將這些標準和規范裝訂成冊,以供開發人員隨時查閱。而且這種方式為了使程序更安全,引入了很多的變量,這樣可能會給我們帶來更多的工作量。這就需要出現一種更方便和強大的防止SQL注入攻擊的技術出現,這就是LINQ的由來。
 
四、LINQ概述

    LINQ在處理SQL注入方面是非常簡單的,在LINQ中加入了標準的模式查詢和更新任何
存儲格式的數據 – 從SQL數據庫到XML文檔甚至到.NET對象。當我們建立數據庫驅動的應用程序時,LING組件可以使開發人員將關系數據作為對象處理,也就是在C#和VB中的"LINQ to SQL",這種技術被認為是ADO.NET家族的數據技術的一部分。這種技術最初以CTP形式引入,因此,LINQ to SQL被稱為DLINQ。

    LINQ to SQL
使我們在應用程序中可以象本地對象一樣對待數據,就象我們在應用程序中對復雜的關系數據和數據連接進行管理(一般將數據庫表映射成類的形式)。事實上,我們可以不寫一行SQL語句通過LINQ演示和操作數據庫中的數據。在運行時,LINQ to SQL將我們的動作翻譯成本地的SQL語句,然后在數據庫中執行。LINQ to SQL將查詢結果作為對象返回,這一過程完全將我們的交互和數據庫以及SQL分割開。目前并沒有比在我們應用程序中消除SQL注入更快的方法。而使用LINQ to SQL,我們卻能做到這一切。

五、通過LINQ使數據訪問更安全

    我們用LINQ to SQL進行數據訪問時,它可以很容易地消除在我們的應用程序中由于SQL注入而帶來的安全隱患,這主要是由于在LINQ中每一個執行的SQL查詢都是參數化的。當使用LINQ建立SQL查詢時,任何提供給查詢的輸入都被看做是參數字符串,無論這個輸入是從哪里來的。開發人員可以在Visual Studio2008中使用集成的LINQ,并通過智能編輯器和編譯時語法檢查來書寫正確的代碼。編譯器可以捕捉很多可能引起功能性錯誤或其他類似的安全隱患的查詢錯誤。與之對比,我們寫的SQL表達式只能在運行時通過數據庫系統對其進行分析和解釋。這樣我們就很難在運行之前知道它們是否正確。曾經有很多攻擊者試著通過對LINQ采取欺騙的手段使其運行非法或具有惡意的SQL語句。但幸運的是,最新的語言和編譯器阻止了這一切的發生。

    心動不如行動,在這里我們來使用LINQ實現一個customer搜索的例子,并使用LINQ來阻止SQL注入的攻擊。第一步是在數據庫中建立和關系數據對應的對象模型。Visual Studio2008包括了一個新的對象關系設計器(也就是O/R設計器),它可以通過拖拽的方式為我們產生全部的對象模型,其中包括對象的設計和它們之間的關系。為了對我們的Northwind中的Customers表建立對象模型,我們需要通過選擇“Add New Item...”,并選擇“LINQ to SQL File”模板(這個模板將打開O/R設計器)在應用程序中建立一個LINQ to SQL文件。為了自動建立完整的Customers表的對象模型,在Server Explorer中選擇這個表,并將它拖到O/R設計器的界面上,如圖2所示。在這個例子中,O/R設計器在應用程序中加入一個Customers.designer.cs文件來定義我們在代碼中使用的類。而不是直接寫代碼和數據庫交互。

     圖2 使用O/R設計器映射Customers表

在定義完Customers表的對象模型類后,我們可以通過customer數據查詢而在代碼中直接查詢數據。在LINQtoSQL.aspx.cs的Page_Load方法中,實例化了被O/R設計器建立的CustomersDataContext類,它重用了在上面例子中SQLInjection.aspx而使用的連接字符串。下面是LINQ查詢獲得的一個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,如果我們提供"Oracle"作為Search的值,那么在運行時和在服務器執行的通過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注入攻擊方法來瀏覽敏感數據,那么將什么也不會顯示出來。

六、小結

    從上面的例子可以看出,使用LINQ是非常容易在Web程序中預防SQL注入攻擊的,當然,也非常容易檢查出這種錯誤。微軟的LINQ to SQL技術使用戶通過對象模型和數據庫進行交互而不是直接使用SQL和數據庫進行交互,從而有效地避免了SQL注入攻擊。這個LINQ結架被C#和Visual Basic建立來格式化字符串和SQL表達式,并阻止SQL注入攻擊的發生,以使開發人員可以將更多的經理集中到程序本身的特性上來。無論我們選擇使用LINQ或是SQL作為.NET應用程序訪問數據的接口,或是設計自己的數據訪問接口,我們都將會做出一個選擇來建立更安全的應用程序。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97