構(gòu)建安全的數(shù)據(jù)訪問(wèn)
本頁(yè)內(nèi)容http://www.microsoft.com/china/technet/security/guidance/secmod87.mspx
本模塊內(nèi)容
數(shù)據(jù)訪問(wèn)是使用幾個(gè)可用的 ADO.NET 數(shù)據(jù)提供程序之一從 ASP.NET Web 應(yīng)用程序訪問(wèn)數(shù)據(jù)庫(kù)的過(guò)程。
此數(shù)據(jù)庫(kù)是應(yīng)用程序級(jí)攻擊的主要目標(biāo)。應(yīng)用程序級(jí)攻擊用于利用數(shù)據(jù)訪問(wèn)代碼中的漏洞并獲取對(duì)數(shù)據(jù)庫(kù)未授權(quán)的訪問(wèn)。如果所有其他攻擊方法都已失效,應(yīng)用程序的前門(mén)(即端口 8)將變成攻擊者竊取、操縱和破壞數(shù)據(jù)的可選路徑。
本模塊說(shuō)明如何構(gòu)建安全的數(shù)據(jù)訪問(wèn)代碼,以及如何避免常見(jiàn)的漏洞和缺陷。本模塊提供了一系列對(duì)策和防御技術(shù),您可以在自己的數(shù)據(jù)訪問(wèn)代碼中使用它們來(lái)減少與數(shù)據(jù)訪問(wèn)有關(guān)的主要威脅。
目標(biāo)
使用本模塊可以實(shí)現(xiàn):
? |
設(shè)計(jì)、構(gòu)建和部署安全的數(shù)據(jù)訪問(wèn)代碼。 |
? |
使用代碼訪問(wèn)安全性和基于角色的安全性可以限制未經(jīng)授權(quán)的調(diào)用方或代碼的訪問(wèn)。 |
? |
安全地驗(yàn)證用戶的身份。 |
? |
防止 SQL 注入攻擊。 |
? |
確保數(shù)據(jù)庫(kù)連接字符串的安全。 |
? |
使用加密機(jī)制來(lái)保護(hù)存儲(chǔ)在數(shù)據(jù)庫(kù)中的數(shù)據(jù)。 |
? |
確保通過(guò)網(wǎng)絡(luò)發(fā)送到數(shù)據(jù)庫(kù)以及從數(shù)據(jù)庫(kù)發(fā)送的數(shù)據(jù)的安全。 |
? |
使用帶有salt 的哈希值將密碼安全地存儲(chǔ)在數(shù)據(jù)庫(kù)中。 |
? |
實(shí)現(xiàn)安全的異常處理。 |
? |
了解如何使用代碼訪問(wèn)安全性,允許中等信任 Web 應(yīng)用程序使用 OLE DB、Oracle 和 ODBC 數(shù)據(jù)提供程序(這些提供程序需要完全信任)。 |
? |
了解應(yīng)使用哪些對(duì)策來(lái)解決常見(jiàn)的數(shù)據(jù)訪問(wèn)威脅,包括 SQL 注入、配置數(shù)據(jù)泄露、敏感的應(yīng)用程序數(shù)據(jù)泄露、數(shù)據(jù)庫(kù)架構(gòu)和連接詳細(xì)信息的泄露、未授權(quán)的訪問(wèn)和網(wǎng)絡(luò)竊聽(tīng)。 |
適用范圍
本模塊適用于下列產(chǎn)品和技術(shù):
? |
Microsoft? Windows? 2000 Server 和 Microsoft Windows Server? 2003 |
? |
Microsoft .NET Framework 1.1 和 ASP.NET 1.1 |
? |
Microsoft SQL Server? |
如何使用本模塊
為了充分理解本模塊內(nèi)容,請(qǐng)先閱讀下列模塊或與本模塊結(jié)合起來(lái)閱讀:
? |
閱讀模塊 2 威脅與對(duì)策。這將使您更廣泛深入地了解 Web 應(yīng)用程序所面臨的潛在威脅及其對(duì)策。 |
? |
閱讀模塊 4 Web 應(yīng)用程序安全設(shè)計(jì)指南。在本模塊中,您將了解構(gòu)建安全解決方案時(shí)所面臨的體系結(jié)構(gòu)和設(shè)計(jì)挑戰(zhàn),以及構(gòu)建準(zhǔn)則。 |
? |
閱讀模塊 18 保證數(shù)據(jù)庫(kù)服務(wù)器的安全。閱讀模塊 18 可了解如何確保數(shù)據(jù)庫(kù)服務(wù)器的安全。 |
? |
閱讀模塊 7 構(gòu)建安全的程序集。模塊 7 中構(gòu)建安全程序集和開(kāi)發(fā)安全托管代碼的準(zhǔn)則和建議同樣應(yīng)該適用于數(shù)據(jù)訪問(wèn)代碼 |
? |
使用評(píng)估模塊。要在產(chǎn)品周期的不同階段檢查數(shù)據(jù)訪問(wèn)的安全性,請(qǐng)參見(jiàn)下列模塊中的“Web 服務(wù)”部分:模塊 5 安全性體系結(jié)構(gòu)和設(shè)計(jì)審查、模塊 21 代碼審查以及模塊 22 部署審查。 |
? |
使用檢查表。本指南“檢查表”部分中的檢查表:保護(hù)數(shù)據(jù)訪問(wèn)包括一個(gè)便于參考的檢查表。可以將此基于任務(wù)的檢查表用作本模塊中各個(gè)建議的摘要。 |
請(qǐng)注意,在當(dāng)前版本的 .NET Framework (1.1) 中,只有 ADO.NET SQL Server 數(shù)據(jù)訪問(wèn)提供程序才支持部分信任調(diào)用方,并且可以安全地用在部分信任 Web 應(yīng)用程序中。OLE DB、Oracle 和 ODBC ADO.NET 數(shù)據(jù)提供程序需要完全信任。
威脅與對(duì)策
要構(gòu)建安全的數(shù)據(jù)訪問(wèn)代碼,需要了解數(shù)據(jù)訪問(wèn)代碼中的威脅是什么、常見(jiàn)漏洞是如何產(chǎn)生的以及如何使用適當(dāng)?shù)膶?duì)策來(lái)降低風(fēng)險(xiǎn)。
數(shù)據(jù)訪問(wèn)代碼面臨的主要威脅包括:
? |
SQL 注入 |
? |
配置數(shù)據(jù)的泄漏 |
? |
敏感應(yīng)用程序數(shù)據(jù)的泄漏 |
? |
數(shù)據(jù)庫(kù)架構(gòu)和連接詳細(xì)信息的泄露 |
? |
未授權(quán)的訪問(wèn) |
? |
網(wǎng)絡(luò)竊聽(tīng) |
圖 14.1 闡明了這些主要威脅。

圖 14.1
數(shù)據(jù)訪問(wèn)代碼面臨的威脅和攻擊
SQL 注入
SQL 注入攻擊利用易受攻擊的數(shù)據(jù)訪問(wèn)代碼,并允許攻擊者在數(shù)據(jù)庫(kù)中執(zhí)行任意命令。如果應(yīng)用程序使用數(shù)據(jù)庫(kù)中不受限制的帳戶,由于攻擊者可以更自由地執(zhí)行查詢和命令,因此受到的威脅會(huì)更大。
漏洞
使數(shù)據(jù)訪問(wèn)代碼容易受到 SQL 注入攻擊的常見(jiàn)漏洞包括:
? |
弱輸入驗(yàn)證 |
? |
在不使用類型安全的參數(shù)時(shí)動(dòng)態(tài)構(gòu)造 SQL 語(yǔ)句 |
? |
使用特權(quán)過(guò)高的數(shù)據(jù)庫(kù)登錄 |
對(duì)策
要應(yīng)對(duì) SQL 注入攻擊,請(qǐng)務(wù)必:
? |
限制和凈化輸入數(shù)據(jù)。 |
? |
使用類型安全的 SQL 參數(shù)進(jìn)行數(shù)據(jù)訪問(wèn)。這些參數(shù)可以與存儲(chǔ)過(guò)程一起使用,也可以是動(dòng)態(tài)構(gòu)造的 SQL 命令字符串。參數(shù)執(zhí)行類型和長(zhǎng)度檢查,并同時(shí)確保注入數(shù)據(jù)庫(kù)中的代碼被視為文本數(shù)據(jù)(而非可執(zhí)行語(yǔ)句)。 |
? |
使用在數(shù)據(jù)庫(kù)中具有有限權(quán)限的帳戶。理想情況下,只應(yīng)向數(shù)據(jù)庫(kù)中的選定存儲(chǔ)過(guò)程授予執(zhí)行權(quán)限,且不提供直接的表格訪問(wèn)權(quán)限。 |
配置數(shù)據(jù)泄露
數(shù)據(jù)訪問(wèn)代碼所使用的最敏感的配置數(shù)據(jù)是數(shù)據(jù)庫(kù)連接字符串。如果泄漏的連接字符串包括用戶名和密碼,后果將不堪設(shè)想。
漏洞
下列漏洞會(huì)增加與泄漏的配置數(shù)據(jù)相關(guān)的安全風(fēng)險(xiǎn):
? |
使用 SQL 身份驗(yàn)證,這要求在連接字符串中指定憑據(jù) |
? |
代碼中嵌入的連接字符串 |
? |
配置文件中的明文連接字符串 |
? |
無(wú)法加密連接字符串 |
對(duì)策
要防止配置數(shù)據(jù)的泄漏:
? |
使用 Windows 身份驗(yàn)證,以便連接字符串中不包含憑據(jù)。 |
? |
加密連接字符串,并限制對(duì)已加密數(shù)據(jù)的訪問(wèn)。 |
敏感應(yīng)用程序數(shù)據(jù)的泄漏
許多應(yīng)用程序都存儲(chǔ)敏感的數(shù)據(jù)(如客戶的信用卡號(hào)),一定要保護(hù)此類數(shù)據(jù)的私密性和完整性。
漏洞
下列編碼做法可能會(huì)導(dǎo)致泄漏敏感的應(yīng)用程序數(shù)據(jù):
? |
存儲(chǔ)沒(méi)有加密的數(shù)據(jù) |
? |
弱授權(quán) |
? |
弱加密 |
對(duì)策
要防止泄漏敏感的應(yīng)用程序數(shù)據(jù):
? |
使用強(qiáng)加密機(jī)制來(lái)確保數(shù)據(jù)的安全。 |
? |
在執(zhí)行數(shù)據(jù)訪問(wèn)之前先為每個(gè)調(diào)用方授權(quán),以便用戶只能看到其各自的數(shù)據(jù)。 |
數(shù)據(jù)庫(kù)架構(gòu)和連接詳細(xì)信息的泄露
如果您的代碼向客戶端返回異常詳細(xì)信息,惡意用戶可能會(huì)使用這些信息來(lái)攻擊服務(wù)器。數(shù)據(jù)訪問(wèn)代碼中的異常可能會(huì)透露敏感信息,如數(shù)據(jù)庫(kù)架構(gòu)詳細(xì)信息、數(shù)據(jù)存儲(chǔ)的特性以及 SQL 代碼片斷。
漏洞
下列漏洞可能會(huì)導(dǎo)致信息泄漏:
? |
不充分的異常處理 |
? |
薄弱的 ASP.NET 配置(允許未經(jīng)處理的異常詳細(xì)信息返回到客戶端) |
對(duì)策
要防止這種泄漏:
? |
捕獲、記錄和處理數(shù)據(jù)訪問(wèn)代碼中的數(shù)據(jù)訪問(wèn)異常。 |
? |
向調(diào)用方返回一般的錯(cuò)誤消息。這要求對(duì) Web.config 或 Machine.config 配置文件中的 <customErrors> 元素進(jìn)行適當(dāng)?shù)呐渲谩?/p> |
未授權(quán)的訪問(wèn)
在授權(quán)不足的情況下,用戶也許能夠看到另一個(gè)用戶的數(shù)據(jù),并且能夠訪問(wèn)其他受限制的數(shù)據(jù)。
漏洞
下列做法可能會(huì)允許未授權(quán)的訪問(wèn):
? |
數(shù)據(jù)訪問(wèn)代碼中缺乏授權(quán),從而提供了不受限制的訪問(wèn) |
? |
數(shù)據(jù)庫(kù)帳戶的特權(quán)過(guò)高 |
對(duì)策
要防止未授權(quán)的訪問(wèn):
? |
按照主體權(quán)限需求為調(diào)用用戶授權(quán)。 |
? |
按照代碼訪問(wèn)安全權(quán)限需求為調(diào)用代碼授權(quán)。 |
? |
使用受限制的權(quán)限來(lái)限制應(yīng)用程序登錄到數(shù)據(jù)庫(kù),并防止直接訪問(wèn)表格。 |
網(wǎng)絡(luò)竊聽(tīng)
大多數(shù)應(yīng)用程序的部署體系結(jié)構(gòu)中都包括數(shù)據(jù)訪問(wèn)代碼與數(shù)據(jù)庫(kù)服務(wù)器之間的物理隔離。因此,必須防止竊聽(tīng)者通過(guò)網(wǎng)絡(luò)竊聽(tīng)敏感數(shù)據(jù)(如應(yīng)用程序特定的數(shù)據(jù)或數(shù)據(jù)庫(kù)登錄憑據(jù))。
漏洞
下列做法會(huì)增加網(wǎng)絡(luò)竊聽(tīng)的漏洞:
? |
在 SQL 身份驗(yàn)證過(guò)程中通過(guò)網(wǎng)絡(luò)傳遞的明文憑據(jù) |
? |
進(jìn)出數(shù)據(jù)庫(kù)服務(wù)器的未加密敏感應(yīng)用程序數(shù)據(jù) |
對(duì)策
要限制網(wǎng)絡(luò)竊聽(tīng)的漏洞:
? |
使用 Windows 身份驗(yàn)證來(lái)避免通過(guò)網(wǎng)絡(luò)發(fā)送憑據(jù)。 |
? |
在數(shù)據(jù)庫(kù)服務(wù)器上安裝一個(gè)服務(wù)器證書(shū)。這會(huì)導(dǎo)致自動(dòng)加密網(wǎng)絡(luò)上的 SQL 憑據(jù)。 |
? |
在 Web 服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器之間使用 SSL 連接來(lái)保護(hù)敏感的應(yīng)用程序數(shù)據(jù)。這需要一個(gè)數(shù)據(jù)庫(kù)服務(wù)器證書(shū)。 |
? |
在 Web 和數(shù)據(jù)庫(kù)服務(wù)器之間使用 IPSec 加密通道。 |
設(shè)計(jì)注意事項(xiàng)
在開(kāi)始編寫(xiě)代碼之前,需要在設(shè)計(jì)時(shí)考慮許多重要的問(wèn)題。主要的注意事項(xiàng)包括:
? |
使用 Windows 身份驗(yàn)證。 |
? |
使用最小特權(quán)帳戶。 |
? |
使用存儲(chǔ)過(guò)程。 |
? |
保護(hù)所存儲(chǔ)的敏感數(shù)據(jù)。 |
? |
使用單獨(dú)的數(shù)據(jù)訪問(wèn)程序集。 |
使用 Windows 身份驗(yàn)證
理想情況下,在設(shè)計(jì)中應(yīng)該使用 Windows 身份驗(yàn)證,以增加安全性好處。使用 Windows 身份驗(yàn)證,您不必存儲(chǔ)具有嵌入憑據(jù)的數(shù)據(jù)庫(kù)連接字符串,憑據(jù)不通過(guò)網(wǎng)絡(luò)傳遞,而且您可以受益于安全帳戶和密碼管理策略。但是,您需要認(rèn)真考慮在使用 Windows 身份驗(yàn)證時(shí),將使用哪個(gè)帳戶連接到 SQL Server。
有關(guān)詳細(xì)信息,請(qǐng)參閱本模塊后面的身份驗(yàn)證。
使用最小特權(quán)帳戶
您的應(yīng)用程序應(yīng)該使用在數(shù)據(jù)庫(kù)中具有有限權(quán)限的最小特權(quán)帳戶。請(qǐng)確保對(duì)應(yīng)用程序的數(shù)據(jù)庫(kù)登錄進(jìn)行了適當(dāng)?shù)氖跈?quán)和限制。有關(guān)詳細(xì)信息,請(qǐng)參閱本模塊后面的授權(quán)。
使用最小特權(quán)帳戶可以降低風(fēng)險(xiǎn),并在您的帳戶發(fā)生泄漏或者注入了惡意代碼時(shí)限制潛在的損害。對(duì)于 SQL 注入,該命令將在由應(yīng)用程序登錄定義的安全上下文中執(zhí)行,并遵守該登錄在數(shù)據(jù)庫(kù)中擁有的相關(guān)權(quán)限。如果您使用特權(quán)過(guò)高的帳戶(例如,作為 SQL Server sysadmin 角色的成員)進(jìn)行連接,攻擊者能夠在服務(wù)器上的任何數(shù)據(jù)庫(kù)中執(zhí)行任意操作。這包括插入、更新和刪除數(shù)據(jù);刪除表;執(zhí)行操作系統(tǒng)命令。
要點(diǎn) 不要使用 sa 帳戶或者 SQL Server sysadmin 或 db_owner 角色的任何成員帳戶連接到 SQL Server。
使用存儲(chǔ)過(guò)程
存儲(chǔ)過(guò)程提供性能、維護(hù)和安全性好處。應(yīng)盡可能使用參數(shù)化存儲(chǔ)過(guò)程進(jìn)行數(shù)據(jù)訪問(wèn)。安全性好處包括:
? |
可以限制應(yīng)用程序數(shù)據(jù)庫(kù)登錄,以便它只具有執(zhí)行指定存儲(chǔ)過(guò)程的權(quán)限。沒(méi)有必要授予直接的表格訪問(wèn)權(quán)限。這有助于降低由 SQL 注入攻擊造成的風(fēng)險(xiǎn)。 |
? |
針對(duì)傳遞到存儲(chǔ)過(guò)程的所有輸入數(shù)據(jù)執(zhí)行長(zhǎng)度和類型檢查。同樣,不能將參數(shù)視為可執(zhí)行代碼。這也會(huì)降低 SQL 注入風(fēng)險(xiǎn)。 |
如果由于某種原因,您無(wú)法使用參數(shù)化存儲(chǔ)過(guò)程,但是您需要?jiǎng)討B(tài)構(gòu)造 SQL 語(yǔ)句,請(qǐng)使用類型化參數(shù)和參數(shù)占位符來(lái)構(gòu)造這樣的語(yǔ)句,以確保檢查輸入數(shù)據(jù)的長(zhǎng)度和類型。
保護(hù)所存儲(chǔ)的敏感數(shù)據(jù)
標(biāo)識(shí)需要保證私密性和完整性的存儲(chǔ)數(shù)據(jù)。如果您只是為了驗(yàn)證而將密碼存儲(chǔ)到數(shù)據(jù)庫(kù)中,請(qǐng)考慮使用單向哈希。如果密碼表發(fā)生泄漏,則不能使用哈希來(lái)獲取明文密碼。
如果您存儲(chǔ)用戶提供的敏感數(shù)據(jù)(如信用卡號(hào)),請(qǐng)使用強(qiáng)對(duì)稱加密算法(如三重 DES (3DES))來(lái)加密數(shù)據(jù)。使用 Win32 數(shù)據(jù)保護(hù) API (DPAPI) 加密 3DES 密鑰,然后將已加密的密鑰存儲(chǔ)在具有受限 ACL 的注冊(cè)表項(xiàng)中,只有管理員和應(yīng)用程序進(jìn)程帳戶才能使用該注冊(cè)表項(xiàng)。
為什么不使用 DPAPI?
盡管建議使用 DPAPI 來(lái)加密連接字符串和其他可在計(jì)算機(jī)出現(xiàn)故障時(shí)手動(dòng)恢復(fù)和重新構(gòu)造的機(jī)密(如帳戶憑據(jù)),但仍不太適合存儲(chǔ)信用卡號(hào)之類的數(shù)據(jù)。這是由于可恢復(fù)性問(wèn)題(如果密鑰丟失,則無(wú)法恢復(fù)加密數(shù)據(jù))和 Web 場(chǎng)問(wèn)題。相反,應(yīng)該使用對(duì)稱加密算法(如 3DES)并使用 DPAPI 加密密鑰。
下面概述了造成 DPAPI 不太適合在數(shù)據(jù)庫(kù)中存儲(chǔ)敏感數(shù)據(jù)的主要問(wèn)題:
? |
如果 DPAPI 與計(jì)算機(jī)密鑰一起使用,而且您將 CRYPTPROTECT_LOCAL_MACHINE 傳遞到 CryptProtectData 和 CryptUnprotectData 函數(shù),則計(jì)算機(jī)帳戶會(huì)生成加密密鑰。這意味著 Web 場(chǎng)中的每臺(tái)服務(wù)器都有一個(gè)不同的密鑰,這會(huì)禁止一臺(tái)服務(wù)器訪問(wèn)由另一臺(tái)服務(wù)器加密的數(shù)據(jù)。同樣,如果該 Web 服務(wù)器計(jì)算機(jī)被破壞,則密鑰會(huì)丟失,而且加密的數(shù)據(jù)無(wú)法從數(shù)據(jù)庫(kù)進(jìn)行恢復(fù)。 |
? |
如果使用計(jì)算機(jī)密鑰方法,則該計(jì)算機(jī)上的任何用戶都可以對(duì)數(shù)據(jù)進(jìn)行解密(除非您使用其他加密機(jī)制)。 |
? |
如果您將 DPAPI 與用戶密鑰一起使用,而且您使用的是本地用戶帳戶,就會(huì)為每臺(tái) Web 服務(wù)器上的每個(gè)本地帳戶生成一個(gè)不同的安全標(biāo)識(shí)符 (SID) 和一個(gè)不同的密鑰,這會(huì)禁止一臺(tái)服務(wù)器訪問(wèn)由另一臺(tái)服務(wù)器加密的數(shù)據(jù)。 |
? |
如果您將 DPAPI 與用戶密鑰一起使用,而且您在 Web 場(chǎng)中的計(jì)算機(jī)之間使用漫游用戶配置文件,則所有數(shù)據(jù)都將共享相同的加密/解密密鑰。但是,如果負(fù)責(zé)漫游用戶配置文件帳戶的域控制器被損害或被破壞,則無(wú)法重新創(chuàng)建具有相同 SID 的用戶帳戶,而且不能從數(shù)據(jù)庫(kù)中恢復(fù)加密的數(shù)據(jù)。 另外,對(duì)于漫游用戶配置文件,如果某人設(shè)法檢索該數(shù)據(jù),則只要攻擊者能夠在特定的用戶帳戶下運(yùn)行代碼,就可以在網(wǎng)絡(luò)中的任何計(jì)算機(jī)上解密該數(shù)據(jù)。這會(huì)增加潛在攻擊的范圍,因此不建議這樣做。 |
使用單獨(dú)的數(shù)據(jù)訪問(wèn)程序集
如果您可以進(jìn)行選擇,請(qǐng)避免將數(shù)據(jù)訪問(wèn)邏輯直接放在 ASP.NET 頁(yè)或代碼隱藏文件中。如果將數(shù)據(jù)訪問(wèn)邏輯放在一個(gè)單獨(dú)的程序集中,并實(shí)現(xiàn)一個(gè)與應(yīng)用程序的業(yè)務(wù)和表示邏輯分開(kāi)的邏輯數(shù)據(jù)訪問(wèn)層,就會(huì)帶來(lái)安全性、重復(fù)使用和維護(hù)好處。
從安全的角度看,您可以:
? |
對(duì)程序集使用強(qiáng)名稱以提供可防篡改功能。 |
? |
使用沙盒技術(shù)來(lái)隔離數(shù)據(jù)訪問(wèn)代碼,如果您的代碼需要支持部分信任調(diào)用方(例如,部分信任 Web 應(yīng)用程序),這一點(diǎn)十分重要。 |
? |
使用那些按照代碼標(biāo)識(shí)權(quán)限需求向調(diào)用代碼授權(quán)的數(shù)據(jù)訪問(wèn)方法和類。 |
對(duì)于深層防御,請(qǐng)按照業(yè)務(wù)組件中的主體權(quán)限需求來(lái)執(zhí)行基于主體的授權(quán),并按照代碼標(biāo)識(shí)權(quán)限需求來(lái)為調(diào)用數(shù)據(jù)訪問(wèn)邏輯的代碼授權(quán),如圖 14.2 所示。

圖 14.2
表示層、業(yè)務(wù)層和數(shù)據(jù)訪問(wèn)層的分離
有關(guān)數(shù)據(jù)訪問(wèn)代碼授權(quán)的詳細(xì)信息,請(qǐng)參閱本模塊后面的授權(quán)部分。
輸入驗(yàn)證
除了業(yè)務(wù)層需要確保數(shù)據(jù)庫(kù)保持?jǐn)?shù)據(jù)的有效性和一致性之外,還必須在將數(shù)據(jù)提交到數(shù)據(jù)庫(kù)之前驗(yàn)證數(shù)據(jù),以防 SQL 注入。如果數(shù)據(jù)訪問(wèn)代碼從當(dāng)前信任邊界內(nèi)部的其他組件接收其輸入內(nèi)容,而且您知道數(shù)據(jù)已經(jīng)過(guò)驗(yàn)證(例如,由 ASP.NET 網(wǎng)頁(yè)或業(yè)務(wù)組件驗(yàn)證),則數(shù)據(jù)訪問(wèn)代碼會(huì)忽略廣泛的數(shù)據(jù)驗(yàn)證。但是,請(qǐng)確保在數(shù)據(jù)訪問(wèn)代碼中使用 SQL 參數(shù),這些參數(shù)驗(yàn)證輸入?yún)?shù)的類型和長(zhǎng)度。下一部分將討論 SQL 參數(shù)的用法。
SQL 注入
當(dāng)應(yīng)用程序使用輸入內(nèi)容來(lái)構(gòu)造動(dòng)態(tài) SQL 語(yǔ)句以訪問(wèn)數(shù)據(jù)庫(kù)時(shí),會(huì)發(fā)生 SQL 注入攻擊。如果代碼使用存儲(chǔ)過(guò)程,而這些存儲(chǔ)過(guò)程作為包含未篩選的用戶輸入的字符串來(lái)傳遞,也會(huì)發(fā)生 SQL 注入攻擊。SQL 注入可能導(dǎo)致攻擊者能夠使用應(yīng)用程序登錄在數(shù)據(jù)庫(kù)中執(zhí)行命令。如果應(yīng)用程序使用特權(quán)過(guò)高的帳戶連接到數(shù)據(jù)庫(kù),這種問(wèn)題會(huì)變得很嚴(yán)重。
注意 傳統(tǒng)的安全措施(如使用 SSL 和 IPSec)不能防止 SQL 注入攻擊。
防止 SQL 注入
使用下列對(duì)策來(lái)防止 SQL 注入攻擊:
? |
限制輸入。 |
? |
使用類型安全的 SQL 參數(shù)。 |
限制輸入
驗(yàn)證輸入內(nèi)容的類型、長(zhǎng)度、格式和范圍。如果您不希望獲得數(shù)值,則不要接受它們。應(yīng)該考慮輸入內(nèi)容來(lái)自何處。如果它來(lái)自受信任源,而且您知道已針對(duì)該來(lái)源執(zhí)行過(guò)徹底的輸入驗(yàn)證,則可以選擇在數(shù)據(jù)訪問(wèn)代碼中忽略數(shù)據(jù)驗(yàn)證。如果數(shù)據(jù)來(lái)自不受信任源或者用于深層防御,則數(shù)據(jù)訪問(wèn)方法和組件應(yīng)該驗(yàn)證輸入。
使用類型安全的 SQL 參數(shù)
SQL 中的 Parameters 集合提供類型檢查和長(zhǎng)度驗(yàn)證。如果您使用 Parameters 集合,則輸入內(nèi)容將被視為文本值,SQL 不會(huì)將其視為可執(zhí)行代碼。使用 Parameters 集合還有一個(gè)好處,那就是可以強(qiáng)制進(jìn)行類型和長(zhǎng)度檢查。超出范圍的值會(huì)觸發(fā)異常。這是深層防御的一個(gè)有力示例。
要點(diǎn) SSL 不能防止 SQL 注入。對(duì)于任何應(yīng)用程序來(lái)說(shuō),如果它在沒(méi)有正確的輸入驗(yàn)證和適當(dāng)?shù)臄?shù)據(jù)訪問(wèn)技術(shù)的情況下訪問(wèn)數(shù)據(jù)庫(kù),都很容易受到 SQL 注入攻擊。
盡可能使用存儲(chǔ)過(guò)程,并使用 Parameters 集合來(lái)調(diào)用它們。
結(jié)合使用 Parameters 集合和存儲(chǔ)過(guò)程
下面的代碼片斷闡釋了 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 參數(shù)被視為文本值,而非可執(zhí)行代碼。另外,還針對(duì)參數(shù)進(jìn)行了類型和長(zhǎng)度檢查。在上例中,輸入值不能長(zhǎng)于 11 個(gè)字符。如果數(shù)據(jù)不遵循由參數(shù)定義的類型或長(zhǎng)度,就會(huì)生成異常。
請(qǐng)注意,使用存儲(chǔ)過(guò)程不一定會(huì)防止 SQL 注入。重要的是結(jié)合使用參數(shù)和存儲(chǔ)過(guò)程。如果不使用參數(shù),則在存儲(chǔ)過(guò)程使用未篩選的輸入內(nèi)容時(shí),它們很容易受到 SQL 注入攻擊。例如,下面的代碼片斷很容易受到攻擊:
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure '" + Login.Text + "'", conn);
要點(diǎn) 如果使用存儲(chǔ)過(guò)程,請(qǐng)確保同時(shí)使用參數(shù)。
結(jié)合使用 Parameters 集合和動(dòng)態(tài) SQL
如果您不能使用存儲(chǔ)過(guò)程,仍可以使用參數(shù),如下面的代碼片斷所示:
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;
使用參數(shù)批處理
通常會(huì)產(chǎn)生如下誤解:如果將幾個(gè) SQL 語(yǔ)句連接在一起,以便在單個(gè)往返中向服務(wù)器發(fā)送一批語(yǔ)句,則不能使用參數(shù)。但是,如果您能確保參數(shù)名不重復(fù),則可以使用這種技術(shù)。通過(guò)在 SQL 文本連接過(guò)程中,向每個(gè)參數(shù)名中添加一個(gè)數(shù)字或其他某個(gè)唯一值,可以方便地執(zhí)行此操作。
使用篩選例程
用來(lái)防止 SQL 注入攻擊的另一種方法是開(kāi)發(fā)篩選例程,以便向具有特殊 SQL 含義的字符添加轉(zhuǎn)義符,如單撇號(hào)字符。下面的代碼片斷闡釋了一個(gè)用來(lái)添加轉(zhuǎn)義符的篩選例程:
private string SafeSqlLiteral(string inputSQL) { return inputSQL.Replace("'", "''"); }
這種例程存在著一定的問(wèn)題,而且您不應(yīng)完全依賴它們,因?yàn)楣粽呖梢允褂?ASCII 十六進(jìn)制字符來(lái)回避檢查。但是應(yīng)該篩選輸入內(nèi)容,并將其作為深層防御策略的一部分。
注意 不要依賴篩選輸入。
使用 LIKE 子句
請(qǐng)注意,如果您使用 LIKE 子句,通配符仍需要轉(zhuǎn)義符。下面的代碼片斷闡釋了這種技術(shù):
s = s.Replace("[", "[[]"); s = s.Replace("%", "[%]"); s = s.Replace("_", "[_]");
身份驗(yàn)證
當(dāng)應(yīng)用程序連接到 SQL Server 數(shù)據(jù)庫(kù)時(shí),可以在 Windows 身份驗(yàn)證或 SQL 身份驗(yàn)證之間進(jìn)行選擇。Windows 身份驗(yàn)證更安全。如果必須使用 SQL 身份驗(yàn)證(可能由于必須使用許多不同的帳戶連接到數(shù)據(jù)庫(kù),并且希望避免調(diào)用 LogonUser),請(qǐng)執(zhí)行其他幾個(gè)步驟,以盡可能降低額外的風(fēng)險(xiǎn)。
注意 如果使用 LogonUser 創(chuàng)建模擬令牌,需要在 Microsoft Windows 2000 上具有功能強(qiáng)大的“作為操作系統(tǒng)的一部分工作”特權(quán),因此應(yīng)避免使用此方法。
考慮下面的建議:
? |
使用 Windows 身份驗(yàn)證。 |
? |
保護(hù) SQL 身份驗(yàn)證的憑據(jù)。 |
? |
使用最小特權(quán)帳戶進(jìn)行連接。 |
使用 Windows 身份驗(yàn)證
Windows 身份驗(yàn)證不通過(guò)網(wǎng)絡(luò)發(fā)送憑據(jù)。如果對(duì) Web 應(yīng)用程序使用 Windows 身份驗(yàn)證,請(qǐng)盡可能使用服務(wù)帳戶或進(jìn)程帳戶(如 ASPNET 帳戶)連接到數(shù)據(jù)庫(kù)。Windows 和 SQL Server 都必須能夠識(shí)別您在數(shù)據(jù)庫(kù)服務(wù)器上使用的帳戶。該帳戶必須被授予 SQL Server 登錄權(quán)限,而且需要具有與訪問(wèn)數(shù)據(jù)庫(kù)相關(guān)的登錄權(quán)限。
在使用 Windows 身份驗(yàn)證時(shí),必須使用受信任連接。下面的代碼片斷顯示了幾個(gè)使用 Windows 身份驗(yàn)證的典型的連接字符串。
下例使用面向 SQL Server 的 ADO.NET 數(shù)據(jù)提供程序:
SqlConnection pubsConn = new SqlConnection( "server=dbserver; database=pubs; Integrated Security=SSPI;");
下例使用面向 OLE DB 數(shù)據(jù)源的 ADO.NET 數(shù)據(jù)提供程序:
OleDbConnection pubsConn = new OleDbConnection( "Provider=SQLOLEDB; Data Source=dbserver; Integrated Security=SSPI;" + "Initial Catalog=northwind");
保護(hù) SQL 身份驗(yàn)證的憑據(jù)
如果必須使用 SQL 身份驗(yàn)證,請(qǐng)確保憑據(jù)不以明文形式通過(guò)網(wǎng)絡(luò)發(fā)送,并確保加密包含憑據(jù)的數(shù)據(jù)庫(kù)連接字符串。
要使 SQL Server 能夠自動(dòng)加密通過(guò)網(wǎng)絡(luò)發(fā)送的憑據(jù),請(qǐng)?jiān)跀?shù)據(jù)庫(kù)服務(wù)器上安裝服務(wù)器證書(shū)。也可以在 Web 服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器之間使用 IPSec 加密通道,來(lái)確保進(jìn)出數(shù)據(jù)庫(kù)服務(wù)器的所有通信的安全。要確保連接字符串的安全,請(qǐng)使用 DPAPI。有關(guān)詳細(xì)信息,請(qǐng)參閱本模塊后面配置管理部分中的“確保連接字符串的安全”。
使用最小特權(quán)帳戶進(jìn)行連接
應(yīng)用程序應(yīng)該通過(guò)使用最小特權(quán)帳戶連接到數(shù)據(jù)庫(kù)。如果您使用 Windows 身份驗(yàn)證進(jìn)行連接,則從操作系統(tǒng)的角度看,Windows 帳戶應(yīng)該是最小特權(quán)帳戶,而且該帳戶應(yīng)該具有有限的特權(quán)和對(duì) Windows 資源的有限的訪問(wèn)能力。另外,無(wú)論您使用 Windows 身份驗(yàn)證還是 SQL 身份驗(yàn)證,相應(yīng)的 SQL Server 登錄都應(yīng)該受到數(shù)據(jù)庫(kù)中的權(quán)限的限制。
有關(guān)如何創(chuàng)建最小特權(quán)數(shù)據(jù)庫(kù)帳戶以及使用 Windows 身份驗(yàn)證將 ASP.NET Web 應(yīng)用程序連接到遠(yuǎn)程數(shù)據(jù)庫(kù)的選項(xiàng)的詳細(xì)信息,請(qǐng)參閱模塊 19 確保 ASP.NET 應(yīng)用程序和 Web 服務(wù)的安全中的“數(shù)據(jù)訪問(wèn)”。
授權(quán)
如果用戶能夠檢索和操縱特定的數(shù)據(jù),就會(huì)建立授權(quán)過(guò)程。有兩種方法:數(shù)據(jù)訪問(wèn)代碼可以使用授權(quán)來(lái)確定是否執(zhí)行請(qǐng)求的操作,數(shù)據(jù)庫(kù)可以通過(guò)執(zhí)行授權(quán)來(lái)限制應(yīng)用程序所使用的 SQL 登錄的功能。
在授權(quán)不足的情況下,用戶也許能夠看到另一個(gè)用戶的數(shù)據(jù),未授權(quán)的用戶也許能夠訪問(wèn)受限制的數(shù)據(jù)。要去除這些威脅:
? |
限制未授權(quán)的調(diào)用方。 |
? |
限制未授權(quán)的代碼。 |
? |
限制數(shù)據(jù)庫(kù)中的應(yīng)用程序。 |
圖 14.3 概述了應(yīng)該使用的授權(quán)點(diǎn)和技術(shù)。

圖 14.3
數(shù)據(jù)訪問(wèn)授權(quán)、程序集和數(shù)據(jù)庫(kù)
注意數(shù)據(jù)訪問(wèn)代碼如何按照權(quán)限需求為調(diào)用用戶或調(diào)用代碼授權(quán)。代碼標(biāo)識(shí)需求是 .NET 代碼訪問(wèn)安全性的一個(gè)特性。
要為數(shù)據(jù)庫(kù)中的應(yīng)用程序授權(quán),請(qǐng)使用只具有執(zhí)行選定存儲(chǔ)過(guò)程權(quán)限的最小特權(quán) SQL 服務(wù)器登錄。除非有特殊理由,否則不應(yīng)為應(yīng)用程序授予如下權(quán)限:直接針對(duì)任何表執(zhí)行創(chuàng)建、檢索、更新、破壞/刪除 (CRUD) 操作。
注意 存儲(chǔ)過(guò)程在數(shù)據(jù)庫(kù)系統(tǒng)的安全上下文中運(yùn)行。盡管您可以通過(guò)為應(yīng)用程序分配對(duì)特定存儲(chǔ)過(guò)程的權(quán)限來(lái)限制它的邏輯操作,但不能限制存儲(chǔ)過(guò)程所執(zhí)行的操作的結(jié)果。存儲(chǔ)過(guò)程是受信任代碼。必須使用數(shù)據(jù)庫(kù)權(quán)限來(lái)確保存儲(chǔ)過(guò)程的接口安全。
限制未授權(quán)的調(diào)用方
您的代碼在連接到數(shù)據(jù)庫(kù)之前必須基于角色或標(biāo)識(shí)為用戶授權(quán)。角色檢查通常用在應(yīng)用程序的業(yè)務(wù)邏輯中,但是,如果您不能清楚地區(qū)分業(yè)務(wù)邏輯和數(shù)據(jù)訪問(wèn)邏輯,請(qǐng)對(duì)數(shù)據(jù)庫(kù)訪問(wèn)方法使用主體權(quán)限需求。
以下屬性確保只有作為 Manager 角色成員的用戶才能調(diào)用 DisplayCustomerInfo 方法:
[PrincipalPermissionAttribute(SecurityAction.Demand, Role="Manager")] public void DisplayCustomerInfo(int CustId) { }
如果需要其他授權(quán)粒度,并且需要在數(shù)據(jù)訪問(wèn)方法內(nèi)部執(zhí)行基于角色的邏輯,請(qǐng)使用命令性主體權(quán)限需求或顯式的角色檢查,如下面的代碼片斷所示:
using System.Security; using System.Security.Permissions; public void DisplayCustomerInfo(int CustId) { try { // 用來(lái)驗(yàn)證調(diào)用方是 manager 的命令性主體權(quán)限 // 角色檢查 PrincipalPermission principalPerm = new PrincipalPermission( null, "Manager"); // 僅在調(diào)用方是“Manager”角色的成員時(shí)才執(zhí)行 // 隨后的代碼 } catch( SecurityException ex ) { . . . } }
下面的代碼片斷使用顯式的程序設(shè)計(jì)角色檢查來(lái)確保調(diào)用方是 Manager 角色的成員:
public void DisplayCustomerInfo(int CustId) { if(!Thread.CurrentPrincipal.IsInRole("Manager")) { . . . } }
限制未授權(quán)的代碼
通過(guò)使用 .NET Framework 代碼訪問(wèn)安全性(特別是代碼標(biāo)識(shí)需求),可以限制能夠訪問(wèn)數(shù)據(jù)訪問(wèn)類和方法的程序集。
例如,如果您只希望由公司或特定開(kāi)發(fā)組織編寫(xiě)的代碼能夠使用您的數(shù)據(jù)訪問(wèn)組件,請(qǐng)使用 StrongNameIdentityPermission ,并要求調(diào)用程序集具有一個(gè)帶有指定公鑰的強(qiáng)名稱,如下面的代碼片斷所示:
using System.Security.Permissions; . . . [StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey="002...4c6")] public void GetCustomerInfo(int CustId) { }
要提取給定程序集的公鑰的文本表示形式,請(qǐng)使用下面的命令:
sn -Tp assembly.dll
注意 在 –Tp 開(kāi)關(guān)中使用大寫(xiě)的“T”。
因?yàn)?Web 應(yīng)用程序的程序集是動(dòng)態(tài)編譯的,所以對(duì)于這些程序集不能使用強(qiáng)名稱。這使得很難將數(shù)據(jù)訪問(wèn)程序集的使用限制在特定的 Web 應(yīng)用程序上。最佳方法是開(kāi)發(fā)一個(gè)自定義權(quán)限,并要求該權(quán)限來(lái)自數(shù)據(jù)訪問(wèn)組件。完全信任 Web 應(yīng)用程序(或任何完全受信任代碼)可以調(diào)用您的組件。但是,部分信任代碼只有在被授予了自定義權(quán)限之后,才能調(diào)用您的數(shù)據(jù)訪問(wèn)組件。
有關(guān)自定義權(quán)限的示例實(shí)現(xiàn),請(qǐng)參閱本指南“如何”部分中的如何:創(chuàng)建自定義加密權(quán)限。
限制數(shù)據(jù)庫(kù)中的應(yīng)用程序
首選方法是為應(yīng)用程序用來(lái)連接到數(shù)據(jù)庫(kù)的 Windows 帳戶創(chuàng)建一個(gè) SQL Server 登錄權(quán)限,然后將 SQL Server 登錄映射到數(shù)據(jù)庫(kù)中的某個(gè)數(shù)據(jù)庫(kù)用戶。將該數(shù)據(jù)庫(kù)用戶放在用戶定義的數(shù)據(jù)庫(kù)角色中,并授予該角色相應(yīng)的權(quán)限。理想情況下,應(yīng)該只為該角色授予對(duì)應(yīng)用程序所使用的存儲(chǔ)過(guò)程的執(zhí)行訪問(wèn)權(quán)限。
有關(guān)如何配置此方法的詳細(xì)信息,請(qǐng)參閱模塊 19 確保 ASP.NET 應(yīng)用程序和 Web 服務(wù)的安全中的“為 ASP.NET 應(yīng)用程序配置數(shù)據(jù)訪問(wèn)權(quán)限”。
配置管理
數(shù)據(jù)庫(kù)連接字符串是針對(duì)數(shù)據(jù)訪問(wèn)代碼主要考慮的配置管理問(wèn)題。應(yīng)認(rèn)真考慮這些字符串的存儲(chǔ)位置以及如何保護(hù)它們(特別是當(dāng)它們包括憑據(jù)時(shí))。要提高加密管理安全性:
? |
使用 Windows 身份驗(yàn)證。 |
? |
確保連接字符串的安全。 |
? |
使用受限制的 ACL 確保 UDL 文件的安全。 |
使用 Window 身份驗(yàn)證
使用 Windows 身份驗(yàn)證時(shí),系統(tǒng)會(huì)為您管理憑據(jù),而且憑據(jù)不會(huì)通過(guò)網(wǎng)絡(luò)傳輸。還可以避免將用戶名和密碼嵌入到連接字符串中。
確保連接字符串的安全
如果您需要使用 SQL 身份驗(yàn)證,連接字符串中將包含用戶名和密碼。如果攻擊者利用 Web 服務(wù)器上的源代碼泄漏這一漏洞或設(shè)法登錄到該服務(wù)器,則攻擊者可以檢索連接字符串。同樣,能夠合法登錄到該服務(wù)器的任何用戶都可以查看它們。使用加密機(jī)制確保連接字符串的安全。
加密連接字符串
使用 DPAPI 加密連接字符串。使用 DPAPI 加密時(shí),由于加密密鑰由平臺(tái)進(jìn)行管理,并且綁定到特定的計(jì)算機(jī)或 Windows 用戶帳戶,因此可避免出現(xiàn)加密密鑰管理問(wèn)題。要使用 DPAPI,必須通過(guò) P/Invoke 調(diào)用 Win32 DPAPI 函數(shù)。
有關(guān)如何構(gòu)建托管包裝類的詳細(xì)信息,請(qǐng)參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。
安全地存儲(chǔ)加密的連接字符串
加密的連接字符串可以放在注冊(cè)表中,也可以放在 Web.config 或 Machine.config 文件中。如果您使用 HKEY_LOCAL_MACHINE 下的注冊(cè)表項(xiàng),請(qǐng)將下面的 ACL 應(yīng)用于該項(xiàng):
管理員:完全控制 進(jìn)程帳戶:讀取
注意 該進(jìn)程帳戶由運(yùn)行數(shù)據(jù)訪問(wèn)程序集的進(jìn)程來(lái)確定。這通常是 ASP.NET 進(jìn)程,或者當(dāng)您的解決方案使用企業(yè)服務(wù)中間層時(shí),該進(jìn)程是企業(yè)服務(wù)服務(wù)器進(jìn)程。
還可以考慮使用 HKEY_CURRENT_USER,該注冊(cè)表項(xiàng)提供受限制的訪問(wèn)。有關(guān)詳細(xì)信息,請(qǐng)參閱模塊 7 構(gòu)建安全的程序集中的“注冊(cè)表”部分。
注意 如果您使用 Microsoft Visual Studio? .NET 數(shù)據(jù)庫(kù)連接向?qū)ВB接字符串將以明文屬性值形式存儲(chǔ)在 Web 應(yīng)用程序代碼隱藏文件或 Web.config 文件中。這兩種方法都應(yīng)該避免使用。
為了更容易部署,您可能希望將加密的字符串存儲(chǔ)在 Web.config 中,盡管這可能不如使用受限制的注冊(cè)表項(xiàng)安全。在本例中,將使用如下所示的自定義 <appSettings> 名稱-值對(duì):
<configuration> <appSettings> <add key="connectionString" value="AQA..bIE=" /> </appSettings> <system.web> ... </system.web> </configuration>
要從 <appSettings> 元素訪問(wèn)密碼文本,請(qǐng)使用如下所示的 ConfigurationSettings 類:
using System.Configuration; private static string GetConnectionString() { return ConfigurationSettings.AppSettings["connectionString"]; }
不要將 Persist Security Info 設(shè)置為“True”或“Yes”
如果在連接字符串中包括 Persist Security Info 屬性,將導(dǎo)致 ConnectionString 屬性在密碼返回給用戶之前,將密碼從連接字符串中去除。在建立與數(shù)據(jù)庫(kù)的連接之后,默認(rèn)設(shè)置 false(等同于忽略 Persist Security Info 屬性)會(huì)丟棄該信息。
使用受限制的 ACL 確保 UDL 文件的安全
如果您的應(yīng)用程序結(jié)合使用外部通用數(shù)據(jù)鏈接 (UDL) 文件和面向 OLE DB 的 ADO.NET 托管數(shù)據(jù)提供程序,請(qǐng)使用 NTFS 權(quán)限來(lái)限制訪問(wèn)。使用以下受限制的 ACL:
管理員:完全控制 進(jìn)程帳戶:讀取
注意 UDL 文件未進(jìn)行加密。一個(gè)更安全的方法是,使用 DPAPI 加密連接字符串,并將其存儲(chǔ)在受限制的注冊(cè)表項(xiàng)中。
敏感數(shù)據(jù)
許多 Web 應(yīng)用程序都在數(shù)據(jù)庫(kù)中以某種形式存儲(chǔ)敏感數(shù)據(jù)。如果攻擊者設(shè)法針對(duì)您的數(shù)據(jù)庫(kù)執(zhí)行查詢,則務(wù)必要適當(dāng)?shù)丶用芩忻舾袛?shù)據(jù)項(xiàng)(如信用卡號(hào))。
? |
加密需要存儲(chǔ)的敏感數(shù)據(jù)。 |
? |
確保網(wǎng)絡(luò)上敏感數(shù)據(jù)的安全。 |
? |
使用帶有salt 的哈希值存儲(chǔ)密碼。 |
加密需要存儲(chǔ)的敏感數(shù)據(jù)
盡可能避免存儲(chǔ)敏感數(shù)據(jù)。如果必須存儲(chǔ)敏感數(shù)據(jù),請(qǐng)對(duì)其進(jìn)行加密。
使用 3DES 加密
要將敏感數(shù)據(jù)(如信用卡號(hào))存儲(chǔ)在數(shù)據(jù)庫(kù)中,請(qǐng)使用強(qiáng)對(duì)稱加密算法,如 3DES。
? |
在開(kāi)發(fā)過(guò)程中,要啟用 3DES 加密
|
? |
在運(yùn)行時(shí),要將加密數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中
|
? |
在運(yùn)行時(shí),要對(duì)加密的機(jī)密進(jìn)行解密
|
在此過(guò)程中,如果用來(lái)對(duì)加密密鑰進(jìn)行加密的 DPAPI 帳戶被損壞,則可以從備份位置檢索 3DES 密鑰的備份,并在新帳戶下使用 DPAPI 對(duì)該備份進(jìn)行加密。新的加密密鑰可以存儲(chǔ)在注冊(cè)表中,數(shù)據(jù)庫(kù)中的數(shù)據(jù)仍可以進(jìn)行解密。
有關(guān)創(chuàng)建托管 DPAPI 庫(kù)的詳細(xì)信息,請(qǐng)參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”中“How To”部分中的“How To: Create a DPAPI Library”,其網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。
保護(hù)網(wǎng)絡(luò)上敏感數(shù)據(jù)的安全
通過(guò)網(wǎng)絡(luò)傳入和傳出數(shù)據(jù)庫(kù)服務(wù)器的敏感數(shù)據(jù)可能包括應(yīng)用程序特定的數(shù)據(jù)或數(shù)據(jù)庫(kù)登錄憑據(jù)。為了確保網(wǎng)絡(luò)上的數(shù)據(jù)的私密性和完整性,可以使用平臺(tái)級(jí)解決方案(如由安全數(shù)據(jù)中心提供的解決方案,在這種解決方案中,在服務(wù)器之間使用 IPSec 加密的通信通道),也可以對(duì)您的應(yīng)用程序進(jìn)行配置,以便與數(shù)據(jù)庫(kù)建立 SSL 連接。后一種方法需要在數(shù)據(jù)庫(kù)服務(wù)器上安裝服務(wù)器證書(shū)。
有關(guān)使用 SSL 和 IPSec 的詳細(xì)信息,請(qǐng)參閱“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”,其網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)
使用帶有salt 的哈希值存儲(chǔ)密碼
如果您需要實(shí)現(xiàn)一個(gè)包含用戶名和密碼的用戶存儲(chǔ),請(qǐng)不要以明文或加密格式來(lái)存儲(chǔ)密碼。存儲(chǔ)增加了 salt 的不可逆哈希值(而不是存儲(chǔ)密碼)可以降低詞典攻擊的風(fēng)險(xiǎn)。
注意 salt 值是密碼形式的強(qiáng)隨機(jī)數(shù)字。
創(chuàng)建 Salt 值
下面的代碼顯示了如何通過(guò)使用隨機(jī)數(shù)字生成功能(此功能由 System.Security.Cryptography 命名空間中的 RNGCryptoServiceProvider 類提供)來(lái)生成 salt 值。
public static string CreateSalt(int size) { RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); byte[] buff = new byte[size]; rng.GetBytes(buff); return Convert.ToBase64String(buff); }
創(chuàng)建 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; }
詳細(xì)信息
有關(guān)實(shí)現(xiàn)用戶存儲(chǔ)(使用帶有salt 的哈希值存儲(chǔ)密碼)的詳細(xì)信息,請(qǐng)參閱“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”,其網(wǎng)址為:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp(英文)。
異常管理
異常條件可能會(huì)由配置錯(cuò)誤、代碼中的錯(cuò)誤或惡意輸入引起。如果沒(méi)有正確的異常管理,這些條件可能會(huì)透露有關(guān)數(shù)據(jù)源位置和特性的敏感信息,以及有價(jià)值的連接詳細(xì)信息。下面的建議適用于數(shù)據(jù)訪問(wèn)代碼:
? |
捕獲和記錄 ADO.NET 異常。 |
? |
確保數(shù)據(jù)庫(kù)連接總是處于斷開(kāi)狀態(tài)。 |
? |
在 ASP.NET 應(yīng)用程序中使用一般錯(cuò)誤頁(yè)面。 |
捕獲和記錄 ADO.NET 異常
將數(shù)據(jù)訪問(wèn)代碼放在 try/catch 塊中并處理異常。在編寫(xiě) ADO.NET 數(shù)據(jù)訪問(wèn)代碼時(shí),由 ADO.NET 生成的異常類型取決于數(shù)據(jù)提供程序。例如:
? |
SQL Server .NET Framework 數(shù)據(jù)提供程序生成 SqlException, |
? |
OLE DB .NET Framework 數(shù)據(jù)提供程序生成 OleDbException, |
? |
ODBC .NET Framework 數(shù)據(jù)提供程序生成 OdbcException。 |
捕獲異常
下面的代碼使用 SQL Server .NET Framework 數(shù)據(jù)提供程序,并顯示應(yīng)該如何捕獲類型為 SqlException 的異常。
try { // 數(shù)據(jù)訪問(wèn)代碼 } catch (SqlException sqlex) // 比較具體 { } catch (Exception ex) // 比較一般 { }
記錄異常
還應(yīng)該記錄來(lái)自 SqlException 類的詳細(xì)信息。此類公開(kāi)那些包含異常條件詳細(xì)信息的屬性。這些屬性包括 Message 屬性(用來(lái)描述錯(cuò)誤)、Number 屬性(用來(lái)唯一標(biāo)識(shí)錯(cuò)誤類型)以及 State 屬性(其中包含其他信息)。State 屬性通常用來(lái)指示特定錯(cuò)誤條件出現(xiàn)的具體位置。例如,如果某個(gè)存儲(chǔ)過(guò)程從多個(gè)行中生成同一錯(cuò)誤,則 State 屬性可以指出錯(cuò)誤出現(xiàn)的具體位置。最后,Errors 集合中包含 SqlError 對(duì)象,這些對(duì)象提供詳細(xì)的 SQL 服務(wù)器錯(cuò)誤信息。
下面的代碼片斷顯示了如何通過(guò)使用 SQL Server .NET Framework 數(shù)據(jù)提供程序來(lái)處理 SQL Server 錯(cuò)誤條件:
using System.Data; using System.Data.SqlClient; using System.Diagnostics; // 由數(shù)據(jù)訪問(wèn)層 (DAL) 組件公開(kāi)的方法 public string GetProductName( int ProductID ) { SqlConnection conn = new SqlConnection( "server=(local);Integrated Security=SSPI;database=products"); // 將所有的數(shù)據(jù)訪問(wèn)代碼包含在 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(); // 在該方法返回之前先執(zhí)行 finally 代碼 return paramPN.Value.ToString(); } catch (SqlException sqlex) { // 處理數(shù)據(jù)訪問(wèn)異常條件 // 記錄具體的異常詳細(xì)信息 LogException(sqlex); // 將當(dāng)前異常包裝在一個(gè)相關(guān)性更強(qiáng)的 // 外部異常中,并重新引發(fā)新異常 throw new Exception( "Failed to retrieve product details for product ID: " + ProductID.ToString(), sqlex ); } finally { conn.Close(); // 確保連接處于斷開(kāi)狀態(tài) } } // Helper 例程,該例程將 SqlException 詳細(xì)信息記錄到 // 應(yīng)用程序事件日志中 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 ); } }
確保數(shù)據(jù)庫(kù)連接總是處于斷開(kāi)狀態(tài)
如果發(fā)生異常,一定要斷開(kāi)數(shù)據(jù)庫(kù)連接,并釋放其他所有受限制的資源。使用 finally 塊或 C# using 語(yǔ)句,可以確保無(wú)論是否發(fā)生了異常條件,都會(huì)斷開(kāi)數(shù)據(jù)庫(kù)連接。上面的代碼闡釋了 finally 塊的用法。還可以按如下方式使用 C# using 語(yǔ)句:
using ((SqlConnection conn = new SqlConnection(connString))) { conn.Open(); // 在以下情況下將斷開(kāi)連接:生成異常或者控制流 // 通常會(huì)離開(kāi) using 語(yǔ)句的使用范圍 }
在 ASP.NET 應(yīng)用程序中使用一般錯(cuò)誤頁(yè)面
如果您的數(shù)據(jù)訪問(wèn)代碼由 ASP.NET Web 應(yīng)用程序或 Web 服務(wù)調(diào)用,則應(yīng)該對(duì) <customErrors> 元素進(jìn)行配置,以防異常詳細(xì)信息傳播回到最終用戶。還可以通過(guò)使用該元素來(lái)指定一般錯(cuò)誤頁(yè)面,如下所示。
<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
對(duì)于生產(chǎn)服務(wù)器設(shè)置 mode="On"。只有在發(fā)布之前開(kāi)發(fā)和測(cè)試軟件時(shí)才使用 mode="Off"。如果不這樣做,將導(dǎo)致向最終用戶返回大量錯(cuò)誤信息(如圖 14.4 中顯示的信息)。這些信息可能包含數(shù)據(jù)庫(kù)服務(wù)器的名稱、數(shù)據(jù)庫(kù)名稱和連接憑據(jù)。

圖 14.4
詳細(xì)的異常信息會(huì)透露敏感數(shù)據(jù)
圖 14.4 還顯示了數(shù)據(jù)訪問(wèn)代碼中接近導(dǎo)致異常的行的大量漏洞。特別是:
? |
連接字符串是硬編碼的。 |
? |
特權(quán)極高的 sa 帳戶用于連接到數(shù)據(jù)庫(kù)。 |
? |
sa 帳戶有一個(gè)弱密碼。 |
? |
SQL 命令的構(gòu)造容易受到 SQL 注入攻擊;輸入內(nèi)容未進(jìn)行驗(yàn)證,代碼不使用參數(shù)化存儲(chǔ)過(guò)程。 |
構(gòu)建安全的數(shù)據(jù)訪問(wèn)組件
下面的代碼顯示了 CheckProductStockLevel 方法(用來(lái)在產(chǎn)品數(shù)據(jù)庫(kù)中查詢庫(kù)存量)的示例實(shí)現(xiàn),該代碼闡釋了本模塊前面介紹的數(shù)據(jù)訪問(wèn)代碼的許多重要安全功能。
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 塊保護(hù)的代碼 try { // (2) 使用正則表達(dá)式驗(yàn)證的輸入內(nèi)容 // 應(yīng)該從資源程序集中檢索錯(cuò)誤消息,以幫助實(shí)現(xiàn) // 本地化。為簡(jiǎn)短起見(jiàn),省略了 Localization(本地化)代碼。 if (Regex.IsMatch(productCode, "^[A-Za-z0-9]{12}$") == false) throw new ArgumentException("Invalid product code" ); //(3) using 語(yǔ)句確保連接被斷開(kāi) using (SqlConnection conn = new SqlConnection(GetConnectionString())) { // (4) 使用參數(shù)化存儲(chǔ)過(guò)程可以應(yīng)對(duì) // SQL 注入攻擊 SqlCommand cmd = new SqlCommand("spCheckProduct", conn); cmd.CommandType = CommandType.StoredProcedure; // 對(duì)參數(shù)的類型進(jìn)行檢查 SqlParameter parm = cmd.Parameters.Add("@ProductCode", SqlDbType.VarChar,12); parm.Value = productCode; // 定義輸出參數(shù) SqlParameter retparm = cmd.Parameters.Add("@quantity", SqlDbType.Int); retparm.Direction = ParameterDirection.Output; conn.Open(); cmd.ExecuteNonQuery(); quantity = (int)retparm.Value; } } catch (SqlException sqlex) { // (5) 記錄完整的異常詳細(xì)信息。一般(安全的)錯(cuò)誤消息 // 基于 SQL 錯(cuò)誤代碼返回調(diào)用方 // 為清楚起見(jiàn),省略了日志和錯(cuò)誤標(biāo)識(shí)代碼 throw new Exception("Error Processing Request"); } catch (Exception ex) { // 記錄完整的異常詳細(xì)信息 throw new Exception("Error Processing Request"); } return quantity; } // (6) 將加密的數(shù)據(jù)庫(kù)連接字符串存保留在注冊(cè)表中 private static string GetConnectionString() { // 從注冊(cè)表中檢索密碼文本;進(jìn)程帳戶必須 // 由注冊(cè)表項(xiàng)的 ACL 授予“讀取”訪問(wèn)權(quán)限 string encryptedString = (string)Registry.LocalMachine.OpenSubKey( @"Software\OrderProcessing\") .GetValue("ConnectionString"); // 使用托管的 DPAPI helper 庫(kù)對(duì)該字符串進(jìn)行解密 DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE); byte[] dataToDecrypt = Convert.FromBase64String(encryptedString); return Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null)); }
上面的代碼顯示出下列安全特征(由注釋行中的數(shù)字進(jìn)行標(biāo)識(shí))。
1. |
數(shù)據(jù)訪問(wèn)代碼放在 try/catch 塊中。這是防止在出現(xiàn)異常時(shí)將系統(tǒng)級(jí)信息返回到調(diào)用方所必需的。調(diào)用 ASP.NET Web 應(yīng)用程序或 Web 服務(wù)會(huì)處理異常,并向客戶端返回適當(dāng)?shù)囊话沐e(cuò)誤消息,但是數(shù)據(jù)訪問(wèn)代碼不依賴這些消息。 |
2. |
使用正則表達(dá)式驗(yàn)證輸入。檢查所提供的產(chǎn)品 ID,以便驗(yàn)證它只包含 A–Z 和 0–9 范圍內(nèi)的字符,而且不超過(guò) 12 個(gè)字符。這是旨在防止 SQL 注入攻擊的一組對(duì)策中的第一個(gè)。 |
3. |
SqlConnection 對(duì)象是在 Microsoft Visual C#? using 語(yǔ)句的內(nèi)部創(chuàng)建的。這可確保無(wú)論是否發(fā)生了異常,都斷開(kāi)方法內(nèi)部的連接。這會(huì)降低拒絕服務(wù)攻擊的威脅,該威脅嘗試使用到數(shù)據(jù)庫(kù)的所有可用連接。通過(guò)使用 finally 塊可以實(shí)現(xiàn)類似的功能。 |
4. |
參數(shù)化存儲(chǔ)過(guò)程用于數(shù)據(jù)訪問(wèn)。這是防止 SQL 注入的另一個(gè)對(duì)策。 |
5. |
不向客戶端返回詳細(xì)的錯(cuò)誤信息。記錄異常詳細(xì)信息,以便幫助診斷問(wèn)題。 |
6. |
加密的數(shù)據(jù)庫(kù)連接字符串存儲(chǔ)在注冊(cè)表中。存儲(chǔ)數(shù)據(jù)庫(kù)連接字符串最安全的方法之一是,使用 DPAPI 加密該字符串,并將加密的密碼文本存儲(chǔ)在具有受限 ACL 的受保護(hù)的注冊(cè)表項(xiàng)中。(例如,使用“管理員:完全控制”和“ASP.NET 或企業(yè)服務(wù)進(jìn)程帳戶:讀取”,具體情況取決于由哪個(gè)進(jìn)程托管該組件。) 注意 該代碼顯示了如何從注冊(cè)表檢索連接字符串,然后使用托管的 DPAPI helper 庫(kù)對(duì)其進(jìn)行解密。此庫(kù)在“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的 How To: Create a DPAPI Library (英文)中提供。 |
代碼訪問(wèn)安全性注意事項(xiàng)
所有的數(shù)據(jù)訪問(wèn)都遵循代碼訪問(wèn)安全權(quán)限需求。您所選擇的 ADO.NET 托管數(shù)據(jù)提供程序可以確定精確的要求。下表顯示了對(duì)于每個(gè) ADO.NET 數(shù)據(jù)提供程序必須授予數(shù)據(jù)訪問(wèn)程序集的權(quán)限。
表 14.1:ADO.NET 數(shù)據(jù)提供程序所需的代碼訪問(wèn)安全權(quán)限
ADO.NET 數(shù)據(jù)提供程序 | 所需的代碼訪問(wèn)安全權(quán)限 |
SQL Server |
SqlClient |
OLE DB |
OleDbPermission* |
Oracle |
OraclePermission* |
ODBC |
OdbcPermission* |
*撰寫(xiě)本文時(shí),在 1.0 和 1.1 版本的 .NET Framework上,OLE DB、Oracle 和 ODBC 提供程序只支持完全信任調(diào)用方。要從部分信任 Web 應(yīng)用程序中使用這些提供程序,必須將您的數(shù)據(jù)訪問(wèn)代碼放在沙盒中,這需要一個(gè)專門(mén)的數(shù)據(jù)訪問(wèn)程序集。有關(guān)顯示如何將數(shù)據(jù)訪問(wèn)代碼放在沙盒中以及如何從中等信任 Web 應(yīng)用程序中使用 OLE DB 數(shù)據(jù)提供程序的示例,請(qǐng)參閱模塊 9 ASP.NET 代碼訪問(wèn)安全性。
如果您使用 ADO.NET SQL Server 數(shù)據(jù)提供程序,您的代碼就必須由代碼訪問(wèn)安全策略授予 SqlClientPermission。完全和中等信任 Web 應(yīng)用程序具有此權(quán)限。
代碼能否連接到 SQL Server 由代碼是否被授予了 SqlClientPermission 來(lái)確定。還可以使用權(quán)限對(duì)數(shù)據(jù)庫(kù)連接字符串的使用進(jìn)行限制。例如,可以強(qiáng)制應(yīng)用程序使用集成安全性,或者可以確保在使用 SQL Server 安全性時(shí)不接受空白密碼。如果違反通過(guò) SqlClientPermission 指定的規(guī)則,將會(huì)導(dǎo)致運(yùn)行時(shí)安全異常。
有關(guān)如何使用 SqlClientPermission 來(lái)限制數(shù)據(jù)訪問(wèn)的詳細(xì)信息,請(qǐng)參閱模塊 8 代碼訪問(wèn)安全的實(shí)踐中的“數(shù)據(jù)訪問(wèn)”。
部署注意事項(xiàng)
以安全方式設(shè)計(jì)和開(kāi)發(fā)的數(shù)據(jù)訪問(wèn)組件如果不以安全的方式進(jìn)行部署,仍然容易受到攻擊。常見(jiàn)的部署做法是使數(shù)據(jù)訪問(wèn)代碼和數(shù)據(jù)庫(kù)駐留在單獨(dú)的服務(wù)器上。這些服務(wù)器通常由內(nèi)部防火墻隔開(kāi),這就引進(jìn)了額外的部署注意事項(xiàng)。開(kāi)發(fā)人員和管理員應(yīng)該了解下列問(wèn)題:
? |
防火墻限制 |
? |
連接字符串管理 |
? |
登錄帳戶配置 |
? |
登錄審核 |
? |
網(wǎng)絡(luò)上的數(shù)據(jù)私密性和完整性 |
防火墻限制
如果您通過(guò)防火墻連接到 SQL Server,請(qǐng)配置防火墻、客戶端和服務(wù)器。可通過(guò)使用 SQL Server 客戶端網(wǎng)絡(luò)實(shí)用程序來(lái)配置客戶端,并使用服務(wù)器網(wǎng)絡(luò)實(shí)用程序配置數(shù)據(jù)庫(kù)服務(wù)器。在默認(rèn)情況下,SQL Server 偵聽(tīng) TCP 端口 1433,但您可以更改此設(shè)置。必須在防火墻上打開(kāi)所選端口。
根據(jù)您所選擇的 SQL Server 身份驗(yàn)證模式以及應(yīng)用程序?qū)Ψ植际绞聞?wù)的使用方式,您可能需要在防火墻上打開(kāi)幾個(gè)其他端口:
? |
如果應(yīng)用程序使用 Windows 身份驗(yàn)證連接到 SQL Server,則必須打開(kāi)支持 Kerberos 或 NTLM 身份驗(yàn)證所必需的端口。 對(duì)于不使用 Active Directory 的網(wǎng)絡(luò),TCP 端口 139 通常是 Windows 身份驗(yàn)證所必需的。有關(guān)端口要求的詳細(xì)信息,請(qǐng)參閱 TechNet 文章“TCP and UDP Port Assignments”和“Security Considerations for Administrative Authority”,前者的網(wǎng)址為:http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/tcpip/part4/tcpappc.asp(英文),后者的網(wǎng)址為:http://www.microsoft.com/technet/security/bestprac/bpent/sec2/seconaa.asp(英文) |
? |
如果您的應(yīng)用程序使用分布式事務(wù)(例如,自動(dòng)化 COM+ 事務(wù)),您可能還需要對(duì)防火墻進(jìn)行配置,以便允許 DTC 通信在單獨(dú)的 DTC 實(shí)例之間以及 DTC 和資源管理器(如 SQL Server)之間流動(dòng)。 |
有關(guān)完整配置的詳細(xì)信息,請(qǐng)參閱模塊 18 保證數(shù)據(jù)庫(kù)服務(wù)器的安全中的“端口”部分。
連接字符串管理
許多應(yīng)用程序都將連接字符串存儲(chǔ)在代碼中,這主要是為了提高性能。但是,性能優(yōu)勢(shì)是可以忽略的,而且使用文件系統(tǒng)緩存有助于確保外部文件中的連接字符串能夠提供相當(dāng)?shù)男阅堋J褂猛獠课募鎯?chǔ)連接字符串對(duì)于系統(tǒng)管理極其有益。
為了增加安全性,建議使用 DPAPI 來(lái)加密連接字符串。如果您的連接字符串包含用戶名和密碼,這一點(diǎn)尤為重要。然后,確定在何處存儲(chǔ)加密的字符串。注冊(cè)表是安全的存儲(chǔ)位置,特別是在您使用 HKEY_CURRENT_USER 時(shí),因?yàn)橹挥性谙嚓P(guān)用戶帳戶下運(yùn)行的進(jìn)程才能進(jìn)行訪問(wèn)。為了使部署更加容易,還可以將加密的字符串存儲(chǔ)在 Web.config 文件中。這兩種方法已在本模塊前面的配置管理部分討論過(guò)。
登錄帳戶配置
一定要讓您的應(yīng)用程序使用最小特權(quán)帳戶來(lái)連接到數(shù)據(jù)庫(kù),這是降低 SQL 注入攻擊威脅的主要方法之一。
作為開(kāi)發(fā)人員,您必須與數(shù)據(jù)庫(kù)管理員進(jìn)行協(xié)商,以確定應(yīng)用程序登錄需要訪問(wèn)的確切的存儲(chǔ)過(guò)程和(可能的)表。在理想情況下,您應(yīng)該只允許應(yīng)用程序登錄對(duì)隨應(yīng)用程序一起部署的一組有限的存儲(chǔ)過(guò)程具有執(zhí)行權(quán)限。
應(yīng)該對(duì) SQL 或 Windows 帳戶、或應(yīng)用程序連接到數(shù)據(jù)庫(kù)所使用的帳戶使用強(qiáng)密碼。
有關(guān)針對(duì)數(shù)據(jù)庫(kù)中的應(yīng)用程序帳戶的建議授權(quán)策略,請(qǐng)參閱本模塊前面的授權(quán)部分。
登錄審核
應(yīng)該將 SQL Server 配置為記錄失敗的登錄嘗試和可能成功的登錄嘗試。審核失敗的登錄嘗試有助于檢測(cè)到嘗試發(fā)現(xiàn)帳戶密碼的攻擊者。
有關(guān)如何配置 SQL Server 審核的詳細(xì)信息,請(qǐng)參閱模塊 18 保證數(shù)據(jù)庫(kù)服務(wù)器的安全。
網(wǎng)絡(luò)上的數(shù)據(jù)私密性和完整性
如果您使用 SQL 身份驗(yàn)證連接到 SQL Server,請(qǐng)確保不通過(guò)網(wǎng)絡(luò)暴露登錄憑據(jù)。可以在數(shù)據(jù)庫(kù)服務(wù)器上安裝一個(gè)證書(shū)(這會(huì)導(dǎo)致 SQL Server 加密憑據(jù)),或者使用數(shù)據(jù)庫(kù)的 IPSec 加密通道。
建議使用數(shù)據(jù)庫(kù)的 IPSec 或 SSL 通道來(lái)保護(hù)傳入和傳出數(shù)據(jù)庫(kù)的敏感的應(yīng)用程序級(jí)數(shù)據(jù)。有關(guān)詳細(xì)信息,請(qǐng)參閱模塊 18 保證數(shù)據(jù)庫(kù)服務(wù)器的安全。
小結(jié)
本模塊顯示了數(shù)據(jù)訪問(wèn)代碼的幾種主要威脅,并重點(diǎn)介紹了常見(jiàn)的漏洞。SQL 注入是應(yīng)該注意的主要威脅之一。除非您使用本模塊中討論的正確對(duì)策,否則攻擊者會(huì)利用您的數(shù)據(jù)訪問(wèn)代碼在數(shù)據(jù)庫(kù)中運(yùn)行任意命令。傳統(tǒng)的安全措施(如防火墻和 SSL)對(duì) SQL 注入攻擊不提供任何防御功能。您應(yīng)該徹底驗(yàn)證自己的輸入內(nèi)容,并將參數(shù)化存儲(chǔ)過(guò)程用作最基本的防御措施。
其他資源
有關(guān)詳細(xì)信息,請(qǐng)參閱下列資源:
? |
有關(guān)可打印的檢查表,請(qǐng)參閱本指南“檢查表”部分中的檢查表:保護(hù)數(shù)據(jù)訪問(wèn)。 |
? |
有關(guān)保護(hù)開(kāi)發(fā)人員工作站的詳細(xì)信息,請(qǐng)參閱本指南“如何”部分中的如何:保護(hù)開(kāi)發(fā)人員工作站。 |
? |
有關(guān)結(jié)合使用 SSL 和 SQL Server 的詳細(xì)信息,請(qǐng)參閱“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”,其網(wǎng)址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT19.asp(英文)。 |
? |
有關(guān)使用 IPSec 的詳細(xì)信息,請(qǐng)參閱“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”,其網(wǎng)址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT18.asp(英文)。 |
? |
有關(guān)使用 DPAPI 的詳細(xì)信息,請(qǐng)參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分中的“How To: Create a DPAPI Library”,其網(wǎng)址為:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT07.asp(英文)。 |
posted on 2006-11-17 15:08 風(fēng)雨兼程 閱讀(430) 評(píng)論(0) 編輯 收藏 所屬分類: Asp.net