網站開發

          asp.net
          隨筆 - 30, 文章 - 0, 評論 - 9, 引用 - 0
          數據加載中……

          構建安全的數據訪問

          本頁內容http://www.microsoft.com/china/technet/security/guidance/secmod87.mspx
          本模塊內容 本模塊內容
          目標 目標
          適用范圍 適用范圍
          如何使用本模塊 如何使用本模塊
          威脅與對策 威脅與對策
          設計注意事項 設計注意事項
          輸入驗證 輸入驗證
          SQL 注入 SQL 注入
          身份驗證 身份驗證
          授權 授權
          配置管理 配置管理
          敏感數據 敏感數據
          異常管理 異常管理
          構建安全的數據訪問組件 構建安全的數據訪問組件
          代碼訪問安全性注意事項 代碼訪問安全性注意事項
          部署注意事項 部署注意事項
          小結 小結
          其他資源 其他資源

          本模塊內容

          數據訪問是使用幾個可用的 ADO.NET 數據提供程序之一從 ASP.NET Web 應用程序訪問數據庫的過程。

          此數據庫是應用程序級攻擊的主要目標。應用程序級攻擊用于利用數據訪問代碼中的漏洞并獲取對數據庫未授權的訪問。如果所有其他攻擊方法都已失效,應用程序的前門(即端口 8)將變成攻擊者竊取、操縱和破壞數據的可選路徑。

          本模塊說明如何構建安全的數據訪問代碼,以及如何避免常見的漏洞和缺陷。本模塊提供了一系列對策和防御技術,您可以在自己的數據訪問代碼中使用它們來減少與數據訪問有關的主要威脅。

          目標

          使用本模塊可以實現:

          ?

          設計、構建和部署安全的數據訪問代碼。

          ?

          使用代碼訪問安全性和基于角色的安全性可以限制未經授權的調用方或代碼的訪問。

          ?

          安全地驗證用戶的身份。

          ?

          防止 SQL 注入攻擊。

          ?

          確保數據庫連接字符串的安全。

          ?

          使用加密機制來保護存儲在數據庫中的數據。

          ?

          確保通過網絡發送到數據庫以及從數據庫發送的數據的安全。

          ?

          使用帶有salt 的哈希值將密碼安全地存儲在數據庫中。

          ?

          實現安全的異常處理。

          ?

          了解如何使用代碼訪問安全性,允許中等信任 Web 應用程序使用 OLE DB、Oracle 和 ODBC 數據提供程序(這些提供程序需要完全信任)。

          ?

          了解應使用哪些對策來解決常見的數據訪問威脅,包括 SQL 注入、配置數據泄露、敏感的應用程序數據泄露、數據庫架構和連接詳細信息的泄露、未授權的訪問和網絡竊聽。

          適用范圍

          本模塊適用于下列產品和技術:

          ?

          Microsoft? Windows? 2000 Server 和 Microsoft Windows Server? 2003

          ?

          Microsoft .NET Framework 1.1 和 ASP.NET 1.1

          ?

          Microsoft SQL Server?

          如何使用本模塊

          為了充分理解本模塊內容,請先閱讀下列模塊或與本模塊結合起來閱讀:

          ?

          閱讀模塊 2 威脅與對策這將使您更廣泛深入地了解 Web 應用程序所面臨的潛在威脅及其對策。

          ?

          閱讀模塊 4 Web 應用程序安全設計指南在本模塊中,您將了解構建安全解決方案時所面臨的體系結構和設計挑戰,以及構建準則。

          ?

          閱讀模塊 18 保證數據庫服務器的安全閱讀模塊 18 可了解如何確保數據庫服務器的安全。

          ?

          閱讀模塊 7 構建安全的程序集模塊 7 中構建安全程序集和開發安全托管代碼的準則和建議同樣應該適用于數據訪問代碼

          ?

          使用評估模塊。要在產品周期的不同階段檢查數據訪問的安全性,請參見下列模塊中的“Web 服務”部分:模塊 5 安全性體系結構和設計審查、模塊 21 代碼審查以及模塊 22 部署審查。

          ?

          使用檢查表。本指南“檢查表”部分中的檢查表:保護數據訪問包括一個便于參考的檢查表。可以將此基于任務的檢查表用作本模塊中各個建議的摘要。

          請注意,在當前版本的 .NET Framework (1.1) 中,只有 ADO.NET SQL Server 數據訪問提供程序才支持部分信任調用方,并且可以安全地用在部分信任 Web 應用程序中。OLE DB、Oracle 和 ODBC ADO.NET 數據提供程序需要完全信任。

          威脅與對策

          要構建安全的數據訪問代碼,需要了解數據訪問代碼中的威脅是什么、常見漏洞是如何產生的以及如何使用適當的對策來降低風險。

          數據訪問代碼面臨的主要威脅包括:

          ?

          SQL 注入

          ?

          配置數據的泄漏

          ?

          敏感應用程序數據的泄漏

          ?

          數據庫架構和連接詳細信息的泄露

          ?

          未授權的訪問

          ?

          網絡竊聽

          圖 14.1 闡明了這些主要威脅。

          數據訪問代碼面臨的威脅和攻擊

          圖 14.1
          數據訪問代碼面臨的威脅和攻擊

          SQL 注入

          SQL 注入攻擊利用易受攻擊的數據訪問代碼,并允許攻擊者在數據庫中執行任意命令。如果應用程序使用數據庫中不受限制的帳戶,由于攻擊者可以更自由地執行查詢和命令,因此受到的威脅會更大。

          漏洞

          使數據訪問代碼容易受到 SQL 注入攻擊的常見漏洞包括:

          ?

          弱輸入驗證

          ?

          在不使用類型安全的參數時動態構造 SQL 語句

          ?

          使用特權過高的數據庫登錄

          對策

          要應對 SQL 注入攻擊,請務必:

          ?

          限制和凈化輸入數據。

          ?

          使用類型安全的 SQL 參數進行數據訪問。這些參數可以與存儲過程一起使用,也可以是動態構造的 SQL 命令字符串。參數執行類型和長度檢查,并同時確保注入數據庫中的代碼被視為文本數據(而非可執行語句)。

          ?

          使用在數據庫中具有有限權限的帳戶。理想情況下,只應向數據庫中的選定存儲過程授予執行權限,且不提供直接的表格訪問權限。

          配置數據泄露

          數據訪問代碼所使用的最敏感的配置數據是數據庫連接字符串。如果泄漏的連接字符串包括用戶名和密碼,后果將不堪設想。

          漏洞

          下列漏洞會增加與泄漏的配置數據相關的安全風險:

          ?

          使用 SQL 身份驗證,這要求在連接字符串中指定憑據

          ?

          代碼中嵌入的連接字符串

          ?

          配置文件中的明文連接字符串

          ?

          無法加密連接字符串

          對策

          要防止配置數據的泄漏:

          ?

          使用 Windows 身份驗證,以便連接字符串中不包含憑據。

          ?

          加密連接字符串,并限制對已加密數據的訪問。

          敏感應用程序數據的泄漏

          許多應用程序都存儲敏感的數據(如客戶的信用卡號),一定要保護此類數據的私密性和完整性。

          漏洞

          下列編碼做法可能會導致泄漏敏感的應用程序數據:

          ?

          存儲沒有加密的數據

          ?

          弱授權

          ?

          弱加密

          對策

          要防止泄漏敏感的應用程序數據:

          ?

          使用強加密機制來確保數據的安全。

          ?

          在執行數據訪問之前先為每個調用方授權,以便用戶只能看到其各自的數據。

          數據庫架構和連接詳細信息的泄露

          如果您的代碼向客戶端返回異常詳細信息,惡意用戶可能會使用這些信息來攻擊服務器。數據訪問代碼中的異常可能會透露敏感信息,如數據庫架構詳細信息、數據存儲的特性以及 SQL 代碼片斷。

          漏洞

          下列漏洞可能會導致信息泄漏:

          ?

          不充分的異常處理

          ?

          薄弱的 ASP.NET 配置(允許未經處理的異常詳細信息返回到客戶端)

          對策

          要防止這種泄漏:

          ?

          捕獲、記錄和處理數據訪問代碼中的數據訪問異常。

          ?

          向調用方返回一般的錯誤消息。這要求對 Web.config 或 Machine.config 配置文件中的 <customErrors> 元素進行適當的配置。

          未授權的訪問

          在授權不足的情況下,用戶也許能夠看到另一個用戶的數據,并且能夠訪問其他受限制的數據。

          漏洞

          下列做法可能會允許未授權的訪問:

          ?

          數據訪問代碼中缺乏授權,從而提供了不受限制的訪問

          ?

          數據庫帳戶的特權過高

          對策

          要防止未授權的訪問:

          ?

          按照主體權限需求為調用用戶授權。

          ?

          按照代碼訪問安全權限需求為調用代碼授權。

          ?

          使用受限制的權限來限制應用程序登錄到數據庫,并防止直接訪問表格。

          網絡竊聽

          大多數應用程序的部署體系結構中都包括數據訪問代碼與數據庫服務器之間的物理隔離。因此,必須防止竊聽者通過網絡竊聽敏感數據(如應用程序特定的數據或數據庫登錄憑據)。

          漏洞

          下列做法會增加網絡竊聽的漏洞:

          ?

          在 SQL 身份驗證過程中通過網絡傳遞的明文憑據

          ?

          進出數據庫服務器的未加密敏感應用程序數據

          對策

          要限制網絡竊聽的漏洞:

          ?

          使用 Windows 身份驗證來避免通過網絡發送憑據。

          ?

          在數據庫服務器上安裝一個服務器證書。這會導致自動加密網絡上的 SQL 憑據。

          ?

          在 Web 服務器和數據庫服務器之間使用 SSL 連接來保護敏感的應用程序數據。這需要一個數據庫服務器證書。

          ?

          在 Web 和數據庫服務器之間使用 IPSec 加密通道。

          設計注意事項

          在開始編寫代碼之前,需要在設計時考慮許多重要的問題。主要的注意事項包括:

          ?

          使用 Windows 身份驗證。

          ?

          使用最小特權帳戶。

          ?

          使用存儲過程。

          ?

          保護所存儲的敏感數據。

          ?

          使用單獨的數據訪問程序集。

          使用 Windows 身份驗證

          理想情況下,在設計中應該使用 Windows 身份驗證,以增加安全性好處。使用 Windows 身份驗證,您不必存儲具有嵌入憑據的數據庫連接字符串,憑據不通過網絡傳遞,而且您可以受益于安全帳戶和密碼管理策略。但是,您需要認真考慮在使用 Windows 身份驗證時,將使用哪個帳戶連接到 SQL Server。

          有關詳細信息,請參閱本模塊后面的身份驗證

          使用最小特權帳戶

          您的應用程序應該使用在數據庫中具有有限權限的最小特權帳戶。請確保對應用程序的數據庫登錄進行了適當的授權和限制。有關詳細信息,請參閱本模塊后面的授權

          使用最小特權帳戶可以降低風險,并在您的帳戶發生泄漏或者注入了惡意代碼時限制潛在的損害。對于 SQL 注入,該命令將在由應用程序登錄定義的安全上下文中執行,并遵守該登錄在數據庫中擁有的相關權限。如果您使用特權過高的帳戶(例如,作為 SQL Server sysadmin 角色的成員)進行連接,攻擊者能夠在服務器上的任何數據庫中執行任意操作。這包括插入、更新和刪除數據;刪除表;執行操作系統命令。

          要點 不要使用 sa 帳戶或者 SQL Server sysadmin db_owner 角色的任何成員帳戶連接到 SQL Server。

          使用存儲過程

          存儲過程提供性能、維護和安全性好處。應盡可能使用參數化存儲過程進行數據訪問。安全性好處包括:

          ?

          可以限制應用程序數據庫登錄,以便它只具有執行指定存儲過程的權限。沒有必要授予直接的表格訪問權限。這有助于降低由 SQL 注入攻擊造成的風險。

          ?

          針對傳遞到存儲過程的所有輸入數據執行長度和類型檢查。同樣,不能將參數視為可執行代碼。這也會降低 SQL 注入風險。

          如果由于某種原因,您無法使用參數化存儲過程,但是您需要動態構造 SQL 語句,請使用類型化參數和參數占位符來構造這樣的語句,以確保檢查輸入數據的長度和類型。

          保護所存儲的敏感數據

          標識需要保證私密性和完整性的存儲數據。如果您只是為了驗證而將密碼存儲到數據庫中,請考慮使用單向哈希。如果密碼表發生泄漏,則不能使用哈希來獲取明文密碼。

          如果您存儲用戶提供的敏感數據(如信用卡號),請使用強對稱加密算法(如三重 DES (3DES))來加密數據。使用 Win32 數據保護 API (DPAPI) 加密 3DES 密鑰,然后將已加密的密鑰存儲在具有受限 ACL 的注冊表項中,只有管理員和應用程序進程帳戶才能使用該注冊表項。

          為什么不使用 DPAPI?

          盡管建議使用 DPAPI 來加密連接字符串和其他可在計算機出現故障時手動恢復和重新構造的機密(如帳戶憑據),但仍不太適合存儲信用卡號之類的數據。這是由于可恢復性問題(如果密鑰丟失,則無法恢復加密數據)和 Web 場問題。相反,應該使用對稱加密算法(如 3DES)并使用 DPAPI 加密密鑰。

          下面概述了造成 DPAPI 不太適合在數據庫中存儲敏感數據的主要問題:

          ?

          如果 DPAPI 與計算機密鑰一起使用,而且您將 CRYPTPROTECT_LOCAL_MACHINE 傳遞到 CryptProtectData CryptUnprotectData 函數,則計算機帳戶會生成加密密鑰。這意味著 Web 場中的每臺服務器都有一個不同的密鑰,這會禁止一臺服務器訪問由另一臺服務器加密的數據。同樣,如果該 Web 服務器計算機被破壞,則密鑰會丟失,而且加密的數據無法從數據庫進行恢復。

          ?

          如果使用計算機密鑰方法,則該計算機上的任何用戶都可以對數據進行解密(除非您使用其他加密機制)。

          ?

          如果您將 DPAPI 與用戶密鑰一起使用,而且您使用的是本地用戶帳戶,就會為每臺 Web 服務器上的每個本地帳戶生成一個不同的安全標識符 (SID) 和一個不同的密鑰,這會禁止一臺服務器訪問由另一臺服務器加密的數據。

          ?

          如果您將 DPAPI 與用戶密鑰一起使用,而且您在 Web 場中的計算機之間使用漫游用戶配置文件,則所有數據都將共享相同的加密/解密密鑰。但是,如果負責漫游用戶配置文件帳戶的域控制器被損害或被破壞,則無法重新創建具有相同 SID 的用戶帳戶,而且不能從數據庫中恢復加密的數據。

          另外,對于漫游用戶配置文件,如果某人設法檢索該數據,則只要攻擊者能夠在特定的用戶帳戶下運行代碼,就可以在網絡中的任何計算機上解密該數據。這會增加潛在攻擊的范圍,因此不建議這樣做。

          使用單獨的數據訪問程序集

          如果您可以進行選擇,請避免將數據訪問邏輯直接放在 ASP.NET 頁或代碼隱藏文件中。如果將數據訪問邏輯放在一個單獨的程序集中,并實現一個與應用程序的業務和表示邏輯分開的邏輯數據訪問層,就會帶來安全性、重復使用和維護好處。

          從安全的角度看,您可以:

          ?

          對程序集使用強名稱以提供可防篡改功能。

          ?

          使用沙盒技術來隔離數據訪問代碼,如果您的代碼需要支持部分信任調用方(例如,部分信任 Web 應用程序),這一點十分重要。

          ?

          使用那些按照代碼標識權限需求向調用代碼授權的數據訪問方法和類。

          對于深層防御,請按照業務組件中的主體權限需求來執行基于主體的授權,并按照代碼標識權限需求來為調用數據訪問邏輯的代碼授權,如圖 14.2 所示。

          分開表示層、業務層和數據訪問層

          圖 14.2
          表示層、業務層和數據訪問層的分離

          有關數據訪問代碼授權的詳細信息,請參閱本模塊后面的授權部分。

          輸入驗證

          除了業務層需要確保數據庫保持數據的有效性和一致性之外,還必須在將數據提交到數據庫之前驗證數據,以防 SQL 注入。如果數據訪問代碼從當前信任邊界內部的其他組件接收其輸入內容,而且您知道數據已經過驗證(例如,由 ASP.NET 網頁或業務組件驗證),則數據訪問代碼會忽略廣泛的數據驗證。但是,請確保在數據訪問代碼中使用 SQL 參數,這些參數驗證輸入參數的類型和長度。下一部分將討論 SQL 參數的用法。

          SQL 注入

          當應用程序使用輸入內容來構造動態 SQL 語句以訪問數據庫時,會發生 SQL 注入攻擊。如果代碼使用存儲過程,而這些存儲過程作為包含未篩選的用戶輸入的字符串來傳遞,也會發生 SQL 注入攻擊。SQL 注入可能導致攻擊者能夠使用應用程序登錄在數據庫中執行命令。如果應用程序使用特權過高的帳戶連接到數據庫,這種問題會變得很嚴重。

          注意 傳統的安全措施(如使用 SSL 和 IPSec)不能防止 SQL 注入攻擊。

          防止 SQL 注入

          使用下列對策來防止 SQL 注入攻擊:

          ?

          限制輸入。

          ?

          使用類型安全的 SQL 參數。

          限制輸入

          驗證輸入內容的類型、長度、格式和范圍。如果您不希望獲得數值,則不要接受它們。應該考慮輸入內容來自何處。如果它來自受信任源,而且您知道已針對該來源執行過徹底的輸入驗證,則可以選擇在數據訪問代碼中忽略數據驗證。如果數據來自不受信任源或者用于深層防御,則數據訪問方法和組件應該驗證輸入。

          使用類型安全的 SQL 參數

          SQL 中的 Parameters 集合提供類型檢查和長度驗證。如果您使用 Parameters 集合,則輸入內容將被視為文本值,SQL 不會將其視為可執行代碼。使用 Parameters 集合還有一個好處,那就是可以強制進行類型和長度檢查。超出范圍的值會觸發異常。這是深層防御的一個有力示例。

          要點 SSL 不能防止 SQL 注入。對于任何應用程序來說,如果它在沒有正確的輸入驗證和適當的數據訪問技術的情況下訪問數據庫,都很容易受到 SQL 注入攻擊。

          盡可能使用存儲過程,并使用 Parameters 集合來調用它們。

          結合使用 Parameters 集合和存儲過程

          下面的代碼片斷闡釋了 Parameters 集合的用法:

          SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);
          myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
          SqlParameter parm = myCommand.SelectCommand.Parameters.Add(
          "@au_id", SqlDbType.VarChar, 11);
          parm.Value = Login.Text;
          

          在本例中,@au_id 參數被視為文本值,而非可執行代碼。另外,還針對參數進行了類型和長度檢查。在上例中,輸入值不能長于 11 個字符。如果數據不遵循由參數定義的類型或長度,就會生成異常。

          請注意,使用存儲過程不一定會防止 SQL 注入。重要的是結合使用參數和存儲過程。如果不使用參數,則在存儲過程使用未篩選的輸入內容時,它們很容易受到 SQL 注入攻擊。例如,下面的代碼片斷很容易受到攻擊:

          SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure '" + 
          Login.Text + "'", conn);
          

          要點 如果使用存儲過程,請確保同時使用參數。

          結合使用 Parameters 集合和動態 SQL

          如果您不能使用存儲過程,仍可以使用參數,如下面的代碼片斷所示:

          SqlDataAdapter myCommand = new SqlDataAdapter(
          "SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);
          SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id", 
          SqlDbType.VarChar, 11);
          parm.Value = Login.Text;
          

          使用參數批處理

          通常會產生如下誤解:如果將幾個 SQL 語句連接在一起,以便在單個往返中向服務器發送一批語句,則不能使用參數。但是,如果您能確保參數名不重復,則可以使用這種技術。通過在 SQL 文本連接過程中,向每個參數名中添加一個數字或其他某個唯一值,可以方便地執行此操作。

          使用篩選例程

          用來防止 SQL 注入攻擊的另一種方法是開發篩選例程,以便向具有特殊 SQL 含義的字符添加轉義符,如單撇號字符。下面的代碼片斷闡釋了一個用來添加轉義符的篩選例程:

          private string SafeSqlLiteral(string inputSQL)
          {
          return inputSQL.Replace("'", "''");
          }
          

          這種例程存在著一定的問題,而且您不應完全依賴它們,因為攻擊者可以使用 ASCII 十六進制字符來回避檢查。但是應該篩選輸入內容,并將其作為深層防御策略的一部分。

          注意 不要依賴篩選輸入。

          使用 LIKE 子句

          請注意,如果您使用 LIKE 子句,通配符仍需要轉義符。下面的代碼片斷闡釋了這種技術:

          s = s.Replace("[", "[[]");
          s = s.Replace("%", "[%]");
          s = s.Replace("_", "[_]");
          

          身份驗證

          當應用程序連接到 SQL Server 數據庫時,可以在 Windows 身份驗證或 SQL 身份驗證之間進行選擇。Windows 身份驗證更安全。如果必須使用 SQL 身份驗證(可能由于必須使用許多不同的帳戶連接到數據庫,并且希望避免調用 LogonUser),請執行其他幾個步驟,以盡可能降低額外的風險。

          注意 如果使用 LogonUser 創建模擬令牌,需要在 Microsoft Windows 2000 上具有功能強大的“作為操作系統的一部分工作”特權,因此應避免使用此方法。

          考慮下面的建議:

          ?

          使用 Windows 身份驗證。

          ?

          保護 SQL 身份驗證的憑據。

          ?

          使用最小特權帳戶進行連接。

          使用 Windows 身份驗證

          Windows 身份驗證不通過網絡發送憑據。如果對 Web 應用程序使用 Windows 身份驗證,請盡可能使用服務帳戶或進程帳戶(如 ASPNET 帳戶)連接到數據庫。Windows 和 SQL Server 都必須能夠識別您在數據庫服務器上使用的帳戶。該帳戶必須被授予 SQL Server 登錄權限,而且需要具有與訪問數據庫相關的登錄權限。

          在使用 Windows 身份驗證時,必須使用受信任連接。下面的代碼片斷顯示了幾個使用 Windows 身份驗證的典型的連接字符串。

          下例使用面向 SQL Server 的 ADO.NET 數據提供程序:

          SqlConnection pubsConn = new SqlConnection(
          "server=dbserver; database=pubs; Integrated Security=SSPI;");
          

          下例使用面向 OLE DB 數據源的 ADO.NET 數據提供程序:

          OleDbConnection pubsConn = new OleDbConnection(
          "Provider=SQLOLEDB; Data Source=dbserver; Integrated Security=SSPI;" +
          "Initial Catalog=northwind");
          

          保護 SQL 身份驗證的憑據

          如果必須使用 SQL 身份驗證,請確保憑據不以明文形式通過網絡發送,并確保加密包含憑據的數據庫連接字符串。

          要使 SQL Server 能夠自動加密通過網絡發送的憑據,請在數據庫服務器上安裝服務器證書。也可以在 Web 服務器和數據庫服務器之間使用 IPSec 加密通道,來確保進出數據庫服務器的所有通信的安全。要確保連接字符串的安全,請使用 DPAPI。有關詳細信息,請參閱本模塊后面配置管理部分中的“確保連接字符串的安全”。

          使用最小特權帳戶進行連接

          應用程序應該通過使用最小特權帳戶連接到數據庫。如果您使用 Windows 身份驗證進行連接,則從操作系統的角度看,Windows 帳戶應該是最小特權帳戶,而且該帳戶應該具有有限的特權和對 Windows 資源的有限的訪問能力。另外,無論您使用 Windows 身份驗證還是 SQL 身份驗證,相應的 SQL Server 登錄都應該受到數據庫中的權限的限制。

          有關如何創建最小特權數據庫帳戶以及使用 Windows 身份驗證將 ASP.NET Web 應用程序連接到遠程數據庫的選項的詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web 服務的安全中的“數據訪問”。

          授權

          如果用戶能夠檢索和操縱特定的數據,就會建立授權過程。有兩種方法:數據訪問代碼可以使用授權來確定是否執行請求的操作,數據庫可以通過執行授權來限制應用程序所使用的 SQL 登錄的功能。

          在授權不足的情況下,用戶也許能夠看到另一個用戶的數據,未授權的用戶也許能夠訪問受限制的數據。要去除這些威脅:

          ?

          限制未授權的調用方。

          ?

          限制未授權的代碼。

          ?

          限制數據庫中的應用程序。

          圖 14.3 概述了應該使用的授權點和技術。

          數據訪問授權、程序集和數據庫

          圖 14.3
          數據訪問授權、程序集和數據庫

          注意數據訪問代碼如何按照權限需求為調用用戶或調用代碼授權。代碼標識需求是 .NET 代碼訪問安全性的一個特性。

          要為數據庫中的應用程序授權,請使用只具有執行選定存儲過程權限的最小特權 SQL 服務器登錄。除非有特殊理由,否則不應為應用程序授予如下權限:直接針對任何表執行創建、檢索、更新、破壞/刪除 (CRUD) 操作。

          注意 存儲過程在數據庫系統的安全上下文中運行。盡管您可以通過為應用程序分配對特定存儲過程的權限來限制它的邏輯操作,但不能限制存儲過程所執行的操作的結果。存儲過程是受信任代碼。必須使用數據庫權限來確保存儲過程的接口安全。

          限制未授權的調用方

          您的代碼在連接到數據庫之前必須基于角色或標識為用戶授權。角色檢查通常用在應用程序的業務邏輯中,但是,如果您不能清楚地區分業務邏輯和數據訪問邏輯,請對數據庫訪問方法使用主體權限需求。

          以下屬性確保只有作為 Manager 角色成員的用戶才能調用 DisplayCustomerInfo 方法:

          [PrincipalPermissionAttribute(SecurityAction.Demand, Role="Manager")]
          public void DisplayCustomerInfo(int CustId)
          {
          }
          

          如果需要其他授權粒度,并且需要在數據訪問方法內部執行基于角色的邏輯,請使用命令性主體權限需求或顯式的角色檢查,如下面的代碼片斷所示:

          using System.Security;
          using System.Security.Permissions;
          
          public void DisplayCustomerInfo(int CustId)
          {
          try
            {
          // 用來驗證調用方是 manager 的命令性主體權限
          // 角色檢查
          PrincipalPermission principalPerm = new PrincipalPermission(
          null, "Manager");
          // 僅在調用方是“Manager”角色的成員時才執行
          // 隨后的代碼
            }
          catch( SecurityException ex )
            {
             . . .
            }
          }
          

          下面的代碼片斷使用顯式的程序設計角色檢查來確保調用方是 Manager 角色的成員:

          public void DisplayCustomerInfo(int CustId)
          {
          if(!Thread.CurrentPrincipal.IsInRole("Manager"))
            {
              . . .
            }
          }
          

          限制未授權的代碼

          通過使用 .NET Framework 代碼訪問安全性(特別是代碼標識需求),可以限制能夠訪問數據訪問類和方法的程序集。

          例如,如果您只希望由公司或特定開發組織編寫的代碼能夠使用您的數據訪問組件,請使用 StrongNameIdentityPermission ,并要求調用程序集具有一個帶有指定公鑰的強名稱,如下面的代碼片斷所示:

          using System.Security.Permissions;
          . . .
          [StrongNameIdentityPermission(SecurityAction.LinkDemand, 
          PublicKey="002...4c6")]
          public void GetCustomerInfo(int CustId)
          {
          }
          

          要提取給定程序集的公鑰的文本表示形式,請使用下面的命令:

          sn -Tp assembly.dll
          

          注意 –Tp 開關中使用大寫的“T”。

          因為 Web 應用程序的程序集是動態編譯的,所以對于這些程序集不能使用強名稱。這使得很難將數據訪問程序集的使用限制在特定的 Web 應用程序上。最佳方法是開發一個自定義權限,并要求該權限來自數據訪問組件。完全信任 Web 應用程序(或任何完全受信任代碼)可以調用您的組件。但是,部分信任代碼只有在被授予了自定義權限之后,才能調用您的數據訪問組件。

          有關自定義權限的示例實現,請參閱本指南“如何”部分中的如何:創建自定義加密權限。

          限制數據庫中的應用程序

          首選方法是為應用程序用來連接到數據庫的 Windows 帳戶創建一個 SQL Server 登錄權限,然后將 SQL Server 登錄映射到數據庫中的某個數據庫用戶。將該數據庫用戶放在用戶定義的數據庫角色中,并授予該角色相應的權限。理想情況下,應該只為該角色授予對應用程序所使用的存儲過程的執行訪問權限。

          有關如何配置此方法的詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web 服務的安全中的“為 ASP.NET 應用程序配置數據訪問權限”。

          配置管理

          數據庫連接字符串是針對數據訪問代碼主要考慮的配置管理問題。應認真考慮這些字符串的存儲位置以及如何保護它們(特別是當它們包括憑據時)。要提高加密管理安全性:

          ?

          使用 Windows 身份驗證。

          ?

          確保連接字符串的安全。

          ?

          使用受限制的 ACL 確保 UDL 文件的安全。

          使用 Window 身份驗證

          使用 Windows 身份驗證時,系統會為您管理憑據,而且憑據不會通過網絡傳輸。還可以避免將用戶名和密碼嵌入到連接字符串中。

          確保連接字符串的安全

          如果您需要使用 SQL 身份驗證,連接字符串中將包含用戶名和密碼。如果攻擊者利用 Web 服務器上的源代碼泄漏這一漏洞或設法登錄到該服務器,則攻擊者可以檢索連接字符串。同樣,能夠合法登錄到該服務器的任何用戶都可以查看它們。使用加密機制確保連接字符串的安全。

          加密連接字符串

          使用 DPAPI 加密連接字符串。使用 DPAPI 加密時,由于加密密鑰由平臺進行管理,并且綁定到特定的計算機或 Windows 用戶帳戶,因此可避免出現加密密鑰管理問題。要使用 DPAPI,必須通過 P/Invoke 調用 Win32 DPAPI 函數。

          有關如何構建托管包裝類的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其網址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

          安全地存儲加密的連接字符串

          加密的連接字符串可以放在注冊表中,也可以放在 Web.config 或 Machine.config 文件中。如果您使用 HKEY_LOCAL_MACHINE 下的注冊表項,請將下面的 ACL 應用于該項:

          管理員:完全控制
          進程帳戶:讀取
          

          注意 該進程帳戶由運行數據訪問程序集的進程來確定。這通常是 ASP.NET 進程,或者當您的解決方案使用企業服務中間層時,該進程是企業服務服務器進程。

          還可以考慮使用 HKEY_CURRENT_USER,該注冊表項提供受限制的訪問。有關詳細信息,請參閱模塊 7 構建安全的程序集中的“注冊表”部分。

          注意 如果您使用 Microsoft Visual Studio? .NET 數據庫連接向導,連接字符串將以明文屬性值形式存儲在 Web 應用程序代碼隱藏文件或 Web.config 文件中。這兩種方法都應該避免使用。

          為了更容易部署,您可能希望將加密的字符串存儲在 Web.config 中,盡管這可能不如使用受限制的注冊表項安全。在本例中,將使用如下所示的自定義 <appSettings> 名稱-值對:

          <configuration>
          <appSettings>  
          <add key="connectionString" value="AQA..bIE=" />
          </appSettings>
          <system.web>
             ...
          </system.web>
          </configuration>
          

          要從 <appSettings> 元素訪問密碼文本,請使用如下所示的 ConfigurationSettings 類:

          using System.Configuration;
          private static string GetConnectionString()
          {
          return ConfigurationSettings.AppSettings["connectionString"];
          }

          不要將 Persist Security Info 設置為“True”或“Yes”

          如果在連接字符串中包括 Persist Security Info 屬性,將導致 ConnectionString 屬性在密碼返回給用戶之前,將密碼從連接字符串中去除。在建立與數據庫的連接之后,默認設置 false(等同于忽略 Persist Security Info 屬性)會丟棄該信息。

          使用受限制的 ACL 確保 UDL 文件的安全

          如果您的應用程序結合使用外部通用數據鏈接 (UDL) 文件和面向 OLE DB 的 ADO.NET 托管數據提供程序,請使用 NTFS 權限來限制訪問。使用以下受限制的 ACL:

          管理員:完全控制
          進程帳戶:讀取
          

          注意 UDL 文件未進行加密。一個更安全的方法是,使用 DPAPI 加密連接字符串,并將其存儲在受限制的注冊表項中。

          敏感數據

          許多 Web 應用程序都在數據庫中以某種形式存儲敏感數據。如果攻擊者設法針對您的數據庫執行查詢,則務必要適當地加密所有敏感數據項(如信用卡號)。

          ?

          加密需要存儲的敏感數據。

          ?

          確保網絡上敏感數據的安全。

          ?

          使用帶有salt 的哈希值存儲密碼。

          加密需要存儲的敏感數據

          盡可能避免存儲敏感數據。如果必須存儲敏感數據,請對其進行加密。

          使用 3DES 加密

          要將敏感數據(如信用卡號)存儲在數據庫中,請使用強對稱加密算法,如 3DES。

          ?

          在開發過程中,要啟用 3DES 加密

          1.

          使用 RNGCryptoServiceProvider 類來生成強(192 位,24 字節)加密密鑰。

          2.

          備份加密密鑰,并將備份副本存儲在物理安全的位置。

          3.

          使用 DPAPI 對密鑰進行加密,并將其存儲在注冊表項中。使用下面的 ACL 來確保注冊表項的安全:

          管理員:完全控制
          進程帳戶(例如,ASPNET):讀取
          ?

          在運行時,要將加密數據存儲在數據庫中

          1.

          獲取要加密的數據。

          2.

          從注冊表中檢索經過加密的加密密鑰。

          3.

          使用 DPAPI 對加密密鑰進行解密。

          4.

          結合使用 TripleDESCryptoServiceProvider 類和加密密鑰來加密數據。

          5.

          將加密數據存儲在數據庫中。

          ?

          在運行時,要對加密的機密進行解密

          1.

          從數據庫中檢索加密數據。

          2.

          從注冊表中檢索經過加密的加密密鑰。

          3.

          使用 DPAPI 對加密密鑰進行解密。

          4.

          使用 TripleDESCryptoServiceProvider 類對加密數據進行解密。

          在此過程中,如果用來對加密密鑰進行加密的 DPAPI 帳戶被損壞,則可以從備份位置檢索 3DES 密鑰的備份,并在新帳戶下使用 DPAPI 對該備份進行加密。新的加密密鑰可以存儲在注冊表中,數據庫中的數據仍可以進行解密。

          有關創建托管 DPAPI 庫的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”中“How To”部分中的“How To: Create a DPAPI Library”,其網址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

          保護網絡上敏感數據的安全

          通過網絡傳入和傳出數據庫服務器的敏感數據可能包括應用程序特定的數據或數據庫登錄憑據。為了確保網絡上的數據的私密性和完整性,可以使用平臺級解決方案(如由安全數據中心提供的解決方案,在這種解決方案中,在服務器之間使用 IPSec 加密的通信通道),也可以對您的應用程序進行配置,以便與數據庫建立 SSL 連接。后一種方法需要在數據庫服務器上安裝服務器證書。

          有關使用 SSL 和 IPSec 的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use IPSec to Provide Secure Communication Between Two Servers”和“How To:Use SSL to Secure Communication to SQL Server 2000”,其網址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)

          使用帶有salt 的哈希值存儲密碼

          如果您需要實現一個包含用戶名和密碼的用戶存儲,請不要以明文或加密格式來存儲密碼。存儲增加了 salt 的不可逆哈希值(而不是存儲密碼)可以降低詞典攻擊的風險。

          注意 salt 值是密碼形式的強隨機數字。

          創建 Salt 值

          下面的代碼顯示了如何通過使用隨機數字生成功能(此功能由 System.Security.Cryptography 命名空間中的 RNGCryptoServiceProvider 類提供)來生成 salt 值。

          public static string CreateSalt(int size)
          {
          RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
          byte[] buff = new byte[size];
          rng.GetBytes(buff);
          return Convert.ToBase64String(buff);
          }

          創建 Hash 值(帶有 Salt)

          下面的代碼片斷顯示了如何從所提供的密碼和 salt 值生成哈希值。

          public static string CreatePasswordHash(string pwd, string salt)
          {
          string saltAndPwd = string.Concat(pwd, salt);
          string hashedPwd = 
          FormsAuthentication.HashPasswordForStoringInConfigFile(
          saltAndPwd, "SHA1");
          return hashedPwd;
          }
          

          詳細信息

          有關實現用戶存儲(使用帶有salt 的哈希值存儲密碼)的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use Forms Authentication with SQL Server 2000”,其網址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。

          異常管理

          異常條件可能會由配置錯誤、代碼中的錯誤或惡意輸入引起。如果沒有正確的異常管理,這些條件可能會透露有關數據源位置和特性的敏感信息,以及有價值的連接詳細信息。下面的建議適用于數據訪問代碼:

          ?

          捕獲和記錄 ADO.NET 異常。

          ?

          確保數據庫連接總是處于斷開狀態。

          ?

          在 ASP.NET 應用程序中使用一般錯誤頁面。

          捕獲和記錄 ADO.NET 異常

          將數據訪問代碼放在 try/catch 塊中并處理異常。在編寫 ADO.NET 數據訪問代碼時,由 ADO.NET 生成的異常類型取決于數據提供程序。例如:

          ?

          SQL Server .NET Framework 數據提供程序生成 SqlException

          ?

          OLE DB .NET Framework 數據提供程序生成 OleDbException

          ?

          ODBC .NET Framework 數據提供程序生成 OdbcException

          捕獲異常

          下面的代碼使用 SQL Server .NET Framework 數據提供程序,并顯示應該如何捕獲類型為 SqlException 的異常。

          try
          {
          // 數據訪問代碼
          }
          catch (SqlException sqlex) // 比較具體
          {
          }
          catch (Exception ex) // 比較一般
          {
          }

          記錄異常

          還應該記錄來自 SqlException 類的詳細信息。此類公開那些包含異常條件詳細信息的屬性。這些屬性包括 Message 屬性(用來描述錯誤)、Number 屬性(用來唯一標識錯誤類型)以及 State 屬性(其中包含其他信息)。State 屬性通常用來指示特定錯誤條件出現的具體位置。例如,如果某個存儲過程從多個行中生成同一錯誤,則 State 屬性可以指出錯誤出現的具體位置。最后,Errors 集合中包含 SqlError 對象,這些對象提供詳細的 SQL 服務器錯誤信息。

          下面的代碼片斷顯示了如何通過使用 SQL Server .NET Framework 數據提供程序來處理 SQL Server 錯誤條件:

          using System.Data;
          using System.Data.SqlClient;
          using System.Diagnostics;
          
          // 由數據訪問層 (DAL) 組件公開的方法
          public string GetProductName( int ProductID )
          {
          SqlConnection conn = new SqlConnection(
          "server=(local);Integrated Security=SSPI;database=products");
          // 將所有的數據訪問代碼包含在 try 塊中
          try
            {
          conn.Open();
          SqlCommand cmd = new SqlCommand("LookupProductName", conn );
          cmd.CommandType = CommandType.StoredProcedure;
          
          cmd.Parameters.Add("@ProductID", ProductID );
          SqlParameter paramPN = 
          cmd.Parameters.Add("@ProductName", SqlDbType.VarChar, 40 );
          paramPN.Direction = ParameterDirection.Output;
          
          cmd.ExecuteNonQuery();
          // 在該方法返回之前先執行 finally 代碼
          return paramPN.Value.ToString();  
            }
          catch (SqlException sqlex)
            {
          // 處理數據訪問異常條件
          // 記錄具體的異常詳細信息
          LogException(sqlex);
          // 將當前異常包裝在一個相關性更強的
          // 外部異常中,并重新引發新異常
          throw new Exception(
          "Failed to retrieve product details for product ID: " + 
          ProductID.ToString(), sqlex );
            }
          finally
            {
          conn.Close(); // 確保連接處于斷開狀態
            }
          }
          
          // Helper 例程,該例程將 SqlException 詳細信息記錄到
          // 應用程序事件日志中
          private void LogException( SqlException sqlex )
          {
          EventLog el = new EventLog();
          el.Source = "CustomAppLog";
          string strMessage;
          strMessage = "Exception Number :" + sqlex.Number + 
          "(" + sqlex.Message + ") has occurred";
          el.WriteEntry( strMessage );
          
          foreach (SqlError sqle in sqlex.Errors)
            {
          strMessage = "Message:" + sqle.Message +
          " Number:" + sqle.Number +
          " Procedure:" + sqle.Procedure +
          " Server:" + sqle.Server +
          " Source:" + sqle.Source +
          " State:" + sqle.State +
          " Severity:" + sqle.Class +
          " LineNumber:" + sqle.LineNumber;
          el.WriteEntry( strMessage );
            }
          }

          確保數據庫連接總是處于斷開狀態

          如果發生異常,一定要斷開數據庫連接,并釋放其他所有受限制的資源。使用 finally 塊或 C# using 語句,可以確保無論是否發生了異常條件,都會斷開數據庫連接。上面的代碼闡釋了 finally 塊的用法。還可以按如下方式使用 C# using 語句:

          using ((SqlConnection conn = new SqlConnection(connString)))
          {
          conn.Open();
          // 在以下情況下將斷開連接:生成異常或者控制流
          // 通常會離開 using 語句的使用范圍
          }

          在 ASP.NET 應用程序中使用一般錯誤頁面

          如果您的數據訪問代碼由 ASP.NET Web 應用程序或 Web 服務調用,則應該對 <customErrors> 元素進行配置,以防異常詳細信息傳播回到最終用戶。還可以通過使用該元素來指定一般錯誤頁面,如下所示。

          <customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
          

          對于生產服務器設置 mode="On"。只有在發布之前開發和測試軟件時才使用 mode="Off"。如果不這樣做,將導致向最終用戶返回大量錯誤信息(如圖 14.4 中顯示的信息)。這些信息可能包含數據庫服務器的名稱、數據庫名稱和連接憑據。

          詳細的異常信息會透露敏感數據

          圖 14.4
          詳細的異常信息會透露敏感數據

          圖 14.4 還顯示了數據訪問代碼中接近導致異常的行的大量漏洞。特別是:

          ?

          連接字符串是硬編碼的。

          ?

          特權極高的 sa 帳戶用于連接到數據庫。

          ?

          sa 帳戶有一個弱密碼。

          ?

          SQL 命令的構造容易受到 SQL 注入攻擊;輸入內容未進行驗證,代碼不使用參數化存儲過程。

          構建安全的數據訪問組件

          下面的代碼顯示了 CheckProductStockLevel 方法(用來在產品數據庫中查詢庫存量)的示例實現,該代碼闡釋了本模塊前面介紹的數據訪問代碼的許多重要安全功能。

          using System;
          using System.Data;
          using System.Data.SqlClient;
          using System.Text.RegularExpressions;
          using System.Collections.Specialized;
          using Microsoft.Win32;
          using DataProtection;
          
          public static int CheckProductStockLevel(string productCode)
          {
          int quantity = 0;
          // (1) 由 try/catch 塊保護的代碼
          try
            {
          // (2) 使用正則表達式驗證的輸入內容
          //     應該從資源程序集中檢索錯誤消息,以幫助實現
          //     本地化。為簡短起見,省略了 Localization(本地化)代碼。
          if (Regex.IsMatch(productCode, "^[A-Za-z0-9]{12}$") == false)
          throw new ArgumentException("Invalid product code" );
          //(3) using 語句確保連接被斷開
          using (SqlConnection conn = new SqlConnection(GetConnectionString()))
              {
          // (4) 使用參數化存儲過程可以應對
          //     SQL 注入攻擊
          SqlCommand cmd = new SqlCommand("spCheckProduct", conn);
          cmd.CommandType = CommandType.StoredProcedure;
          
          // 對參數的類型進行檢查
          SqlParameter parm = 
          cmd.Parameters.Add("@ProductCode", 
          SqlDbType.VarChar,12);
          parm.Value = productCode;
          // 定義輸出參數
          SqlParameter retparm = cmd.Parameters.Add("@quantity", SqlDbType.Int);
          retparm.Direction = ParameterDirection.Output;
          conn.Open();
          cmd.ExecuteNonQuery();
          quantity = (int)retparm.Value;
              }
            }
          catch (SqlException sqlex)
            {
          // (5) 記錄完整的異常詳細信息。一般(安全的)錯誤消息
          //     基于 SQL 錯誤代碼返回調用方
          //     為清楚起見,省略了日志和錯誤標識代碼
          throw new Exception("Error Processing Request");
            }
          catch (Exception ex)
            {
          // 記錄完整的異常詳細信息
          throw new Exception("Error Processing Request");
            }
          return quantity;
          }
          
          // (6) 將加密的數據庫連接字符串存保留在注冊表中
          private static string GetConnectionString()
          {
          // 從注冊表中檢索密碼文本;進程帳戶必須
          // 由注冊表項的 ACL 授予“讀取”訪問權限
          string encryptedString = (string)Registry.LocalMachine.OpenSubKey(
          @"Software\OrderProcessing\")
          .GetValue("ConnectionString");
          // 使用托管的 DPAPI helper 庫對該字符串進行解密
          DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE);
          byte[] dataToDecrypt = Convert.FromBase64String(encryptedString);
          return Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null));
          }
          

          上面的代碼顯示出下列安全特征(由注釋行中的數字進行標識)。

          1.

          數據訪問代碼放在 try/catch 塊中。這是防止在出現異常時將系統級信息返回到調用方所必需的。調用 ASP.NET Web 應用程序或 Web 服務會處理異常,并向客戶端返回適當的一般錯誤消息,但是數據訪問代碼不依賴這些消息。

          2.

          使用正則表達式驗證輸入。檢查所提供的產品 ID,以便驗證它只包含 A–Z 和 0–9 范圍內的字符,而且不超過 12 個字符。這是旨在防止 SQL 注入攻擊的一組對策中的第一個。

          3.

          SqlConnection 對象是在 Microsoft Visual C#? using 語句的內部創建的。這可確保無論是否發生了異常,都斷開方法內部的連接。這會降低拒絕服務攻擊的威脅,該威脅嘗試使用到數據庫的所有可用連接。通過使用 finally 塊可以實現類似的功能。

          4.

          參數化存儲過程用于數據訪問。這是防止 SQL 注入的另一個對策。

          5.

          不向客戶端返回詳細的錯誤信息。記錄異常詳細信息,以便幫助診斷問題。

          6.

          加密的數據庫連接字符串存儲在注冊表中。存儲數據庫連接字符串最安全的方法之一是,使用 DPAPI 加密該字符串,并將加密的密碼文本存儲在具有受限 ACL 的受保護的注冊表項中。(例如,使用“管理員:完全控制”和“ASP.NET 或企業服務進程帳戶:讀取”,具體情況取決于由哪個進程托管該組件。)

          注意 該代碼顯示了如何從注冊表檢索連接字符串,然后使用托管的 DPAPI helper 庫對其進行解密。此庫在“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的 How To: Create a DPAPI Library (英文)中提供。

          代碼訪問安全性注意事項

          所有的數據訪問都遵循代碼訪問安全權限需求。您所選擇的 ADO.NET 托管數據提供程序可以確定精確的要求。下表顯示了對于每個 ADO.NET 數據提供程序必須授予數據訪問程序集的權限。

          表 14.1:ADO.NET 數據提供程序所需的代碼訪問安全權限

          ADO.NET 數據提供程序 所需的代碼訪問安全權限

          SQL Server

          SqlClient
          PermissionSupports 部分信任調用方(包括中等信任 Web 應用程序)。

          OLE DB

          OleDbPermission*

          Oracle

          OraclePermission*

          ODBC

          OdbcPermission*

          *撰寫本文時,在 1.0 和 1.1 版本的 .NET Framework上,OLE DB、Oracle 和 ODBC 提供程序只支持完全信任調用方。要從部分信任 Web 應用程序中使用這些提供程序,必須將您的數據訪問代碼放在沙盒中,這需要一個專門的數據訪問程序集。有關顯示如何將數據訪問代碼放在沙盒中以及如何從中等信任 Web 應用程序中使用 OLE DB 數據提供程序的示例,請參閱模塊 9 ASP.NET 代碼訪問安全性。

          如果您使用 ADO.NET SQL Server 數據提供程序,您的代碼就必須由代碼訪問安全策略授予 SqlClientPermission。完全和中等信任 Web 應用程序具有此權限。

          代碼能否連接到 SQL Server 由代碼是否被授予了 SqlClientPermission 來確定。還可以使用權限對數據庫連接字符串的使用進行限制。例如,可以強制應用程序使用集成安全性,或者可以確保在使用 SQL Server 安全性時不接受空白密碼。如果違反通過 SqlClientPermission 指定的規則,將會導致運行時安全異常。

          有關如何使用 SqlClientPermission 來限制數據訪問的詳細信息,請參閱模塊 8 代碼訪問安全的實踐中的“數據訪問”。

          部署注意事項

          以安全方式設計和開發的數據訪問組件如果不以安全的方式進行部署,仍然容易受到攻擊。常見的部署做法是使數據訪問代碼和數據庫駐留在單獨的服務器上。這些服務器通常由內部防火墻隔開,這就引進了額外的部署注意事項。開發人員和管理員應該了解下列問題:

          ?

          防火墻限制

          ?

          連接字符串管理

          ?

          登錄帳戶配置

          ?

          登錄審核

          ?

          網絡上的數據私密性和完整性

          防火墻限制

          如果您通過防火墻連接到 SQL Server,請配置防火墻、客戶端和服務器。可通過使用 SQL Server 客戶端網絡實用程序來配置客戶端,并使用服務器網絡實用程序配置數據庫服務器。在默認情況下,SQL Server 偵聽 TCP 端口 1433,但您可以更改此設置。必須在防火墻上打開所選端口。

          根據您所選擇的 SQL Server 身份驗證模式以及應用程序對分布式事務的使用方式,您可能需要在防火墻上打開幾個其他端口:

          ?

          如果應用程序使用 Windows 身份驗證連接到 SQL Server,則必須打開支持 Kerberos 或 NTLM 身份驗證所必需的端口。

          對于不使用 Active Directory 的網絡,TCP 端口 139 通常是 Windows 身份驗證所必需的。有關端口要求的詳細信息,請參閱 TechNet 文章“TCP and UDP Port Assignments”和“Security Considerations for Administrative Authority”,前者的網址為:http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/tcpip/part4/tcpappc.asp(英文),后者的網址為:http://www.microsoft.com/technet/security/bestprac/bpent/sec2/seconaa.asp(英文)

          ?

          如果您的應用程序使用分布式事務(例如,自動化 COM+ 事務),您可能還需要對防火墻進行配置,以便允許 DTC 通信在單獨的 DTC 實例之間以及 DTC 和資源管理器(如 SQL Server)之間流動。

          有關完整配置的詳細信息,請參閱模塊 18 保證數據庫服務器的安全中的“端口”部分。

          連接字符串管理

          許多應用程序都將連接字符串存儲在代碼中,這主要是為了提高性能。但是,性能優勢是可以忽略的,而且使用文件系統緩存有助于確保外部文件中的連接字符串能夠提供相當的性能。使用外部文件存儲連接字符串對于系統管理極其有益。

          為了增加安全性,建議使用 DPAPI 來加密連接字符串。如果您的連接字符串包含用戶名和密碼,這一點尤為重要。然后,確定在何處存儲加密的字符串。注冊表是安全的存儲位置,特別是在您使用 HKEY_CURRENT_USER 時,因為只有在相關用戶帳戶下運行的進程才能進行訪問。為了使部署更加容易,還可以將加密的字符串存儲在 Web.config 文件中。這兩種方法已在本模塊前面的配置管理部分討論過。

          登錄帳戶配置

          一定要讓您的應用程序使用最小特權帳戶來連接到數據庫,這是降低 SQL 注入攻擊威脅的主要方法之一。

          作為開發人員,您必須與數據庫管理員進行協商,以確定應用程序登錄需要訪問的確切的存儲過程和(可能的)表。在理想情況下,您應該只允許應用程序登錄對隨應用程序一起部署的一組有限的存儲過程具有執行權限。

          應該對 SQL 或 Windows 帳戶、或應用程序連接到數據庫所使用的帳戶使用強密碼。

          有關針對數據庫中的應用程序帳戶的建議授權策略,請參閱本模塊前面的授權部分。

          登錄審核

          應該將 SQL Server 配置為記錄失敗的登錄嘗試和可能成功的登錄嘗試。審核失敗的登錄嘗試有助于檢測到嘗試發現帳戶密碼的攻擊者。

          有關如何配置 SQL Server 審核的詳細信息,請參閱模塊 18 保證數據庫服務器的安全。

          網絡上的數據私密性和完整性

          如果您使用 SQL 身份驗證連接到 SQL Server,請確保不通過網絡暴露登錄憑據。可以在數據庫服務器上安裝一個證書(這會導致 SQL Server 加密憑據),或者使用數據庫的 IPSec 加密通道。

          建議使用數據庫的 IPSec 或 SSL 通道來保護傳入和傳出數據庫的敏感的應用程序級數據。有關詳細信息,請參閱模塊 18 保證數據庫服務器的安全。

          小結

          本模塊顯示了數據訪問代碼的幾種主要威脅,并重點介紹了常見的漏洞。SQL 注入是應該注意的主要威脅之一。除非您使用本模塊中討論的正確對策,否則攻擊者會利用您的數據訪問代碼在數據庫中運行任意命令。傳統的安全措施(如防火墻和 SSL)對 SQL 注入攻擊不提供任何防御功能。您應該徹底驗證自己的輸入內容,并將參數化存儲過程用作最基本的防御措施。

          其他資源

          有關詳細信息,請參閱下列資源:

          ?

          有關可打印的檢查表,請參閱本指南“檢查表”部分中的檢查表:保護數據訪問。

          ?

          有關保護開發人員工作站的詳細信息,請參閱本指南“如何”部分中的如何:保護開發人員工作站。

          ?

          有關結合使用 SSL 和 SQL Server 的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use SSL to Secure Communication with SQL Server 2000”,其網址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT19.asp(英文)。

          ?

          有關使用 IPSec 的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Use IPSec to Provide Secure Communication Between Two Servers”,其網址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT18.asp(英文)。

          ?

          有關使用 DPAPI 的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其網址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT07.asp(英文)。


          posted on 2006-11-17 15:08 風雨兼程 閱讀(430) 評論(0)  編輯  收藏 所屬分類: Asp.net

          主站蜘蛛池模板: 鄂尔多斯市| 华安县| 蓬莱市| 辽源市| 南丰县| 罗城| 沅江市| 阳曲县| 桓台县| 景宁| 湖口县| 邛崃市| 温宿县| 固安县| 长丰县| 重庆市| 日喀则市| 清涧县| 泾川县| 旺苍县| 东乌珠穆沁旗| 莲花县| 乳源| 广昌县| 五台县| 贞丰县| 铁岭市| 越西县| 伊通| 祁门县| 台南县| 仁化县| 芦溪县| 民权县| 玉门市| 阜平县| 沈阳市| 依安县| 贵德县| 正定县| 张北县|