程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 使用LINQ解除SQL注入安全問題

使用LINQ解除SQL注入安全問題

編輯:關於.NET

在開發人員承受越來越多的安全責任之時,許多開發人員了解到的第一個Web 應用安全漏洞,是一個被稱為“SQL注入”的極危險的命令注入形式 。命令注入的原始的形式本是指這樣一種漏洞:攻擊者通過提供一個正常使用者 意料之外的輸入,改變你的Web應用程序的運行方式,從而允許攻擊者運行服務 器上的非授權的命令。無疑,SQL注入式攻擊是很常見的、被廣泛使用的攻擊形 式。幸運的是,一旦我們理解了這個問題,就可以很容易地防止SQL注入式攻擊 。更妙的是,現在微軟的數據訪問技術向.net開發人員提供了徹底地清除SQL注 入漏洞的機會,當然前提是能夠正確使用。這種技術稱為“語言級集成查 詢”(Language Integrated Query (LINQ)),並隨Visual Studio "Orcas" 和 .NET Framework 3.5一起發布。本文將討論如何通過 LINQ強化Web應用程序的數據訪問代碼,從而解決通過SQL注入進行攻擊的問題。

SQL注入是一種Web應用程序的安全漏洞,通過它攻擊者可以將惡意數據 提交給應用程序,欺騙應用程序在服務器上執行惡意的SQL命令。理論上講,這 種攻擊是容易預防的,不過由於其允許攻擊者直接運行針對用戶關鍵數據的數據庫命令,從而成為一種常見的、危害性大的攻擊形式。在非常極端的情況下,攻 擊者不但能夠自由地控制用戶的數據,還可以刪除數據表和數據庫,甚至控制整 個數據庫服務器。

如果這種攻擊容易預防,那麼為什麼還如此危險呢? 首先,由於眾所周知的經濟上的原因,你的應用數據庫是非常誘人的,可以引起 攻擊者的極大注意。如果SQL注入漏洞在Web應用程序中可能存在著,那麼對於一 個攻擊者來說是很容易檢測到的,然後就可以利用它。很顯然,即使SQL注入錯 誤並不是開發人員最經常犯的錯誤,它們也很容易被發現和利用。

對SQL 注入的剖析

這裡我們給出一個SQL注入的例子來說明兩個問題,一是SQL 注入這種錯誤是很容易犯的,二是只要進行嚴格的程序設計,這種錯誤是很容易 預防的。

這個示例用的Web應用程序包含一個名為SQLInjection.aspx簡 單的客戶搜索頁面,這個頁面易於受到SQL注入攻擊。此頁面包含一個 CompanyName的輸入服務器控件,還有一個數據表格控件,用於顯示從微軟的示 例數據庫Northwind的搜索結果(這個數據庫可從SQL Server 2005中找到)。在 搜索期間執行的這個查詢包含一個應用程序設計中很普通的錯誤:它動態地從用 戶提供的輸入中生成查詢。這是Web應用程序數據訪問中的一個主要的錯誤,因 為這樣實際上潛在地相信了用戶輸入,並直接將其發送給你的服務器。在從 “搜索”的單擊事件啟動時,這個查詢看起來是這個樣子:

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;
}

在這種情況下,如果一個用戶輸入“Ernst Handel”作為公司名,並單擊“搜索”按鈕,作為響應屏幕會 向用戶顯示那個公司的記錄,這正是我們所期望的理想情況。不過一個攻擊者可 以輕易地操縱這個動態查詢。例如,攻擊者通過插入一個UNION子句,並用一個 注釋符號終止這個語句的剩余部分。換句話說,攻擊者不是輸入“Ernst Handel”,而是輸入如下的內容:

Ernst Handel' UNION SELECT CustomerID, ShipName, ShipAddress
FROM ORDERS--

其結果是這個SQL語句在服務器端執行,由於添加了這個惡意的請求 。它會將這個動態的SQL查詢轉換為下面的樣子:

SELECT [CustomerID], [CompanyName],
[ContactName]
FROM [Customers]
WHERE CompanyName ='Ernst Handel'
UNION SELECT CustomerID, ShipName,
ShipAddress
FROM ORDERS-- '

這是一個相當合法的SQL語句,它可以在應用程序數據庫上執行 ,返回order表中所有的客戶,這些客戶通過應用程序已經處理了定單。

典型的SQL防護

可以看出,在你的應用程序中創造並利用一個SQL注入漏 洞是多麼容易。幸運的是,如前所述,只需要采取幾項簡單的對策通常就可以預 防SQL注入攻擊。最常用的、成本效率最高的預防SQL注入攻擊的方法是驗證應用 程序中所有的最終用於數據訪問的數據輸入。用戶發出的任何輸入,不管是通過 Web應用程序輸入的或者是常駐於數據存儲設備的,都要在服務器處理你的數據 訪問命令之前在服務器端驗證其類型、長度、格式和范圍。不幸的是,基於代碼 的對策並不十分安全,而且有可能失敗,特別是當發生如下情況時:

驗 證程序設計不當

驗證僅在客戶層面執行

在應用程序中,驗證時遺 漏了字段(有時即使是一個字段)。

防止SQL注入的另外一層涉及正確地 確定應用程序中所有SQL查詢的參數,不管是在動態SQL語句中還是在存儲過程中 。例如,如果代碼像下面這樣構建查詢,就比較安全:

SELECT [CustomerID], [CompanyName], [ContactName]
FROM [Customers]
WHERE CompanyName = @CompanyName

當作為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 = 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應用程序開發的一部分,還是對它進 行花樣翻新,用於現有的實際應用程序的數據訪問,你都是作了一個構建更安全 的應用程序的選擇。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved