共用方式為


保護連接字串與其他設定資訊 (C#)

作者:Scott Mitchell

下載 PDF

ASP.NET 應用程式通常會將組態資訊儲存在 Web.config 檔案中。 其中一些資訊很機密,而且需要保護。 根據預設,此檔案不會提供給網站訪客,但系統管理員或駭客可能會取得網頁伺服器檔系統的存取權,並檢視檔案的內容。 在本教學課程中,我們瞭解 ASP.NET 2.0 可讓我們透過加密 Web.config 檔案的區段來保護敏感性資訊。

簡介

ASP.NET 應用程式的組態資訊通常會儲存在名為 的 Web.configXML 檔案中。 在這些教學課程的課程中,我們已更新 Web.config 數次。 在第一個教學課程中建立Northwind具類型的數據集時,連接字串 信息會自動新增至 Web.config<connectionStrings>段中。 稍後,在 主版頁面和網站導覽 教學課程中,我們會手動更新 Web.config,新增元素 <pages> ,指出專案中的所有 ASP.NET 頁面都應該使用 DataWebControls 主題。

由於 Web.config 可能包含敏感數據,例如連接字串,因此請務必將 的內容 Web.config 保持安全且隱藏於未經授權的檢視者。 根據預設,擴展名為檔案 .config 的任何 HTTP 要求都是由 ASP.NET 引擎處理,這會傳回圖 1 所示 的這個頁面類型訊息 。 這表示訪客無法直接輸入http://www.YourServer.com/Web.config瀏覽器的網址列來檢視您的Web.config檔案內容。

流覽 Web.config 透過瀏覽器傳回此類型的頁面未提供訊息

圖 1:瀏覽 Web.config 瀏覽器傳回此類型的頁面未提供訊息 (按兩下即可檢視大小完整的影像)

但是,如果攻擊者能夠找到一些允許她檢視檔案 Web.config 內容的其他惡意探索,該怎麼辦? 攻擊者可以使用這項資訊做什麼,以及可以採取哪些步驟來進一步保護內的 Web.config敏感性資訊? 幸運的是,中的 Web.config 大部分區段不包含敏感性資訊。 如果攻擊者知道您 ASP.NET 頁面使用的預設主題名稱,攻擊者可能會造成什麼傷害?

不過,某些 Web.config 區段包含可能包含連接字串、使用者名稱、密碼、伺服器名稱、加密密鑰等敏感性資訊。 此資訊通常是在下列 Web.config 各節中找到:

  • <appSettings>
  • <connectionStrings>
  • <identity>
  • <sessionState>

在本教學課程中,我們將探討保護這類敏感性組態信息的技術。 如我們所見,.NET Framework 2.0 版包含受保護的組態系統,可讓程式設計方式加密和解密選取的組態區段。

注意

本教學課程將探討 Microsoft 從 ASP.NET 應用程式連線到資料庫的建議。 除了加密連接字串之外,您還可以確保以安全的方式連線到資料庫,以協助強化系統。

步驟 1:探索 ASP.NET 2.0 s 受保護的組態選項

ASP.NET 2.0 包含受保護的組態系統,用於加密和解密組態資訊。 這包括 .NET Framework 中可用來以程式設計方式加密或解密組態資訊的方法。 受保護的組態系統會使用提供者模型,讓開發人員選擇所使用的密碼編譯實作。

.NET Framework 隨附兩個受保護的組態提供者:

由於受保護的組態系統會實作提供者設計模式,因此可以建立您自己的受保護組態提供者,並將其插入您的應用程式。 如需此程式的詳細資訊 ,請參閱實作受保護的設定提供者

RSA 和 DPAPI 提供者會使用金鑰進行其加密和解密例程,而且這些密鑰可以儲存在電腦或使用者層級。 計算機層級金鑰適用於 Web 應用程式在其專屬伺服器上執行的情況,或如果伺服器上有多個應用程式需要共用加密信息的情況。 在共用裝載環境中,用戶層級密鑰是更安全的選項,其中相同伺服器上的其他應用程式應該無法解密應用程式受保護的組態區段。

在本教學課程中,我們的範例將使用 DPAPI 提供者和機器層級密鑰。 具體而言,我們將探討在 中Web.config加密 區<connectionStrings>段,雖然受保護的組態系統可用來加密大部分的任何Web.config區段。 如需使用用戶層級密鑰或使用 RSA 提供者的資訊,請參閱本教學課程結尾的一節中的資源。

注意

RSAProtectedConfigurationProviderDPAPIProtectedConfigurationProvider 提供者會分別在檔案中machine.config註冊提供者名稱和 RsaProtectedConfigurationProviderDataProtectionConfigurationProvider。 加密或解密組態資訊時, RsaProtectedConfigurationProvider 我們需要提供適當的提供者名稱 (或 DataProtectionConfigurationProvider) ,而不是實際類型名稱 (RSAProtectedConfigurationProviderDPAPIProtectedConfigurationProvider) 。 您可以在資料夾中找到檔案machine.config$WINDOWS$\Microsoft.NET\Framework\version\CONFIG

步驟 2:以程式設計方式加密和解密組態區段

使用幾行程式代碼,我們可以使用指定的提供者來加密或解密特定組態區段。 如我們稍後所見,程式代碼只需要以程式設計方式參考適當的組態區段、呼叫其 ProtectSectionUnprotectSection 方法,然後呼叫 Save 方法來保存變更。 此外,.NET Framework 包含實用的命令行公用程式,可加密和解密組態資訊。 我們將在步驟 3 中探索此命令行公用程式。

為了以程式設計方式保護組態資訊,讓我們建立一個 ASP.NET 頁面,其中包含用來加密和解密 中的 Web.config<connectionStrings>段的按鈕。

首先, EncryptingConfigSections.aspx 開啟資料夾中的頁面 AdvancedDAL 。 將 TextBox 控制件從 [工具箱] 拖曳至 Designer,並將其 屬性分別設定ID為 、其 TextMode 屬性設定為 MultiLine,並將 和 RowsWidth 屬性分別設定為 95% WebConfigContents和 15。 此 TextBox 控制件會顯示的內容 Web.config ,讓我們快速查看內容是否已加密。 當然,在實際應用程式中,您永遠不會想要顯示 的內容 Web.config

在 TextBox 底下,新增兩個名為 EncryptConnStrings 和的 DecryptConnStringsButton 控件。 將其 Text 屬性設定為 [加密連接字串] 和 [解密連接字串]。

此時,您的畫面看起來應該類似圖 2。

顯示 Visual Studio 已開啟至 [EncryptingConfigSections.aspx] 頁面的螢幕快照,其中包含新的 TextBox 和兩個 Button 控件。

圖 2:將 TextBox 和兩個按鈕 Web 控件新增至頁面 (按兩下即可檢視大小完整的影像)

接下來,我們需要撰寫程序代碼,以在第一次載入頁面時載入及顯示 TextBox 中WebConfigContents的內容Web.config。 將下列程式代碼新增至頁面的程式代碼後置類別。 當 為 時,此程式代碼會新增名為 DisplayWebConfig 的方法,並從事件處理程式呼叫它Page_LoadPage.IsPostBackfalse

protected void Page_Load(object sender, EventArgs e)
{
    // On the first page visit, call DisplayWebConfig method
    if (!Page.IsPostBack)
        DisplayWebConfig();
}
private void DisplayWebConfig()
{
    // Reads in the contents of Web.config and displays them in the TextBox
    StreamReader webConfigStream = 
        File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"));
    string configContents = webConfigStream.ReadToEnd();
    webConfigStream.Close();
    WebConfigContents.Text = configContents;
}

方法DisplayWebConfigFile使用 類別來開啟應用程式檔案Web.configStreamReader將內容讀入字串的 類別,以及 Path 產生檔案實體路徑的 Web.config 類別。 這三個類別全都位於 命名空間中System.IO。 因此,您必須將語句新增 usingSystem.IO 至程式代碼後置類別的頂端,或者,將這些類別名稱前面加上 System.IO.

接下來,我們需要新增兩個 Button 控制事件 Click 的事件處理程式,並新增必要的程式代碼,以搭配 DPAPI 提供者使用機器層級金鑰加密和解密 <connectionStrings> 區段。 從 Designer 中,按兩下每個 Buttons,在程式代碼後置類別中新增Click事件處理程式,然後新增下列程式代碼:

protected void EncryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only encrypt the section if it is not already protected
        if (!connectionStrings.SectionInformation.IsProtected)
        {
            // Encrypt the <connectionStrings> section using the 
            // DataProtectionConfigurationProvider provider
            connectionStrings.SectionInformation.ProtectSection(
                "DataProtectionConfigurationProvider");
            config.Save();
            
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}
protected void DecryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = 
        config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only decrypt the section if it is protected
        if (connectionStrings.SectionInformation.IsProtected)
        {
            // Decrypt the <connectionStrings> section
            connectionStrings.SectionInformation.UnprotectSection();
            config.Save();
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}

兩個事件處理程式中使用的程式代碼幾乎完全相同。 兩者一開始都是透過 WebConfigurationManager 類別 s OpenWebConfiguration 方法取得目前應用程式Web.config檔案的相關信息。 這個方法會傳回指定之虛擬路徑的 Web 組態檔。 接下來,檔案 Web.config s 區段是透過 類別 s <connectionStrings>GetSection(sectionName) 方法來存取,這個方法會ConfigurationSectionConfiguration回 物件。

ConfigurationSection物件包含屬性SectionInformation,提供有關組態區段的其他資訊和功能。 如上述程式代碼所示,我們可以檢查 SectionInformation 屬性 s IsProtected 屬性來判斷組態區段是否加密。 此外,區段也可以透過 SectionInformation 屬性和 ProtectSection(provider)UnprotectSection 方法進行加密或解密。

方法 ProtectSection(provider) 接受做為輸入字串,指定加密時要使用的受保護組態提供者名稱。 在 Button 事件處理程式中 EncryptConnString ,我們會將 DataProtectionConfigurationProvider 傳遞至 方法, ProtectSection(provider) 以便使用 DPAPI 提供者。 方法 UnprotectSection 可以判斷用來加密組態區段的提供者,因此不需要任何輸入參數。

呼叫 或 方法之後,您必須呼叫 Configuration 物件 s Save 方法來保存變更。UnprotectSectionProtectSection(provider) 設定信息經過加密或解密並儲存變更之後,我們會呼叫 DisplayWebConfig 將更新 Web.config 的內容載入 TextBox 控制件。

輸入上述程式代碼之後,請透過瀏覽器瀏覽 EncryptingConfigSections.aspx 頁面來測試它。 您一開始應該會看到一個頁面,其中列出以純文本顯示區段的內容Web.config<connectionStrings>, (請參閱圖 3) 。

顯示網頁瀏覽器中載入EncryptingConfigSections.aspx頁面的螢幕快照。

圖 3:將 TextBox 和兩個按鈕 Web 控件新增至頁面 (按兩下即可檢視大小完整的影像)

現在,按兩下 [加密連接字串] 按鈕。 如果啟用要求驗證,則從 TextBox 傳回的 WebConfigContents 標記會產生 HttpRequestValidationException,以顯示來自客戶端的潛在危險 Request.Form 值。 預設會在 ASP.NET 2.0 中啟用要求驗證,禁止包含未編碼 HTML 的回傳,並設計來協助防止腳本插入式攻擊。 此檢查可以在頁面或應用層級停用。 若要關閉此頁面的設定,請將 ValidateRequest 指示詞中的 @Page 設定false設為 。 指示 @Page 詞位於頁面宣告式標記的頂端。

<%@ Page ValidateRequest="False" ... %>

如需要求驗證、其用途、如何在頁面和應用層級停用,以及如何 HTML 編碼標記的詳細資訊,請參閱 要求驗證 - 防止腳本攻擊

停用頁面的要求驗證之後,請嘗試再次按兩下 [加密連接字串] 按鈕。 在回傳時,將會使用 DPAPI 提供者存取組態檔及其 <connectionStrings> 區段加密。 然後會更新 TextBox 以顯示新 Web.config 內容。 如圖 4 所示, <connectionStrings> 信息現在已加密。

按兩下 [加密連接字串] 按鈕 [ <加密 connectionString]> 區段

圖 4:按兩下 [加密連接字串] 按鈕 [ <connectionString> 加密區段] (按鍵即可檢視完整大小的映像)

我的計算機上產生的加密 <connectionStrings> 區段會遵循,雖然已移除 元素中的 <CipherData> 部分內容,但為了簡潔起見:

<connectionStrings 
    configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/...zChw==</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

注意

元素 <connectionStrings> 會指定用來執行加密 () DataProtectionConfigurationProvider 的提供者。 按兩下 [解密連接字串] 按鈕時, UnprotectSection 方法會使用這項資訊。

從存取 連接字串 資訊Web.config時- 由我們撰寫的程式代碼、從 SqlDataSource 控件,或從具型別數據集中的 TableAdapters 自動產生的程式代碼進行解密。 簡單地說,我們不需要新增任何額外的程式代碼或邏輯來解密加密的 <connectionString> 區段。 若要示範這一點,請流覽目前其中一個先前的教學課程,例如基本報告一節中的簡單顯示教學課程 (~/BasicReporting/SimpleDisplay.aspx) 。 如圖 5 所示,本教學課程的運作方式與預期完全相同,指出 ASP.NET 頁面會自動解密加密 連接字串 資訊。

數據存取層會自動解密連接字串資訊

圖 5:數據存取層會自動解密連接字串資訊, (按兩下即可檢視完整大小的映像)

若要將 <connectionStrings> 區段還原回其純文本表示法,請按兩下 [解密連接字串] 按鈕。 在回傳時,您應該會在純文字中看到 Web.config 連接字串。 此時,當您第一次流覽此頁面時,畫面看起來應該像這樣, (圖 3) 中看到。

步驟 3:使用 aspnet_regiis.exe 加密組態區段

.NET Framework 包含資料夾中的各種命令行工具$WINDOWS$\Microsoft.NET\Framework\version\。 例如,在 [使用 SQL 快取相依性 ] 教學課程中,我們查看了如何使用 aspnet_regsql.exe 命令行工具來新增 SQL 快取相依性所需的基礎結構。 此資料夾中的另一個實用命令列 工具是 ASP.NET IIS 註冊工具 (aspnet_regiis.exe) 。 如其名所示,ASP.NET IIS 註冊工具主要用於向 Microsoft 專業等級 Web 伺服器 IIS 註冊 ASP.NET 2.0 應用程式。 除了 IIS 相關功能之外,ASP.NET IIS 註冊工具也可以用來加密或解密 中的 Web.config指定組態區段。

下列語句顯示用來使用命令列工具加密組態區段的 aspnet_regiis.exe 一般語法:

aspnet_regiis.exe -pef section physical_directory -prov provider

section 是用來加密 (的組態區段,例如 connectionStrings ) 、 physical_directory 是 Web 應用程式根目錄的完整實體路徑,而 provider 是受保護的組態提供者名稱,可用來 (,例如 DataProtectionConfigurationProvider ) 。 或者,如果在 IIS 中註冊 Web 應用程式,您可以使用下列語法來輸入虛擬路徑,而不是實體路徑:

aspnet_regiis.exe -pe section -app virtual_directory -prov provider

下列 aspnet_regiis.exe 範例會使用 DPAPI 提供者搭配電腦層級金鑰來加密 <connectionStrings> 區段:

aspnet_regiis.exe -pef
"connectionStrings" "C:\Websites\ASPNET_Data_Tutorial_73_CS"
-prov "DataProtectionConfigurationProvider"

同樣地, aspnet_regiis.exe 命令行工具也可以用來解密組態區段。 不要使用 -pef 參數,請使用 -pdf (或 ,而不是 -pe,請使用 -pd) 。 此外,請注意,解密時不需要提供者名稱。

aspnet_regiis.exe -pdf section physical_directory
  -- or --
aspnet_regiis.exe -pd section -app virtual_directory

注意

由於我們使用 DPAPI 提供者,其使用電腦特定的金鑰,因此您必須從提供網頁的相同電腦執行 aspnet_regiis.exe 。 例如,如果您從本機開發計算機執行此命令行程式,然後將加密的 Web.config 檔案上傳至生產伺服器,則生產伺服器將無法解密 連接字串 資訊,因為它已使用開發計算機特定的密鑰進行加密。 RSA 提供者沒有這項限制,因為可以將 RSA 金鑰匯出到另一部電腦。

瞭解資料庫驗證選項

任何應用程式都必須先識別要求者,才能對 Microsoft SQL Server 資料庫發出 SELECTINSERTUPDATE、 或 DELETE 查詢。 此程式稱為驗證,SQL Server 提供兩種驗證方法:

  • Windows 驗證 - 應用程式執行所在的進程會用來與資料庫通訊。 透過 Visual Studio 2005 s ASP.NET Development Server 執行 ASP.NET 應用程式時,ASP.NET 應用程式會假設目前登入使用者的身分識別。 對於 Microsoft Internet Information Server (IIS) 上的 ASP.NET 應用程式,ASP.NET 應用程式通常會假設 或 domainName``\NETWORK SERVICEdomainName``\MachineName身分識別,不過這可以自定義。
  • SQL 驗證 - 提供使用者識別碼和密碼值作為驗證的認證。 使用 SQL 驗證時,會在 連接字串 中提供使用者識別碼和密碼。

Windows 驗證 優先於 SQL 驗證,因為它更安全。 透過 Windows 驗證,連接字串 用戶名稱和密碼是免費的,而且如果網頁伺服器和資料庫伺服器位於兩部不同的計算機上,則認證不會以純文本透過網路傳送。 不過,使用 SQL 驗證時,驗證認證會在 連接字串 中硬式編碼,並以純文本形式從網頁伺服器傳輸至資料庫伺服器。

這些教學課程已使用 Windows 驗證。 您可以藉由檢查 連接字串 來告知正在使用的驗證模式。 我們的教學課程 連接字串Web.config::

Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\NORTHWND.MDF; Integrated Security=True; User Instance=True

整合式安全性=True 且缺少使用者名稱和密碼,表示正在使用 Windows 驗證。 在某些連接字串中,會使用 Trusted Connection=Yes 或 Integrated Security=SSPI 一詞,而不是 Integrated Security=True,但這三個都表示使用 Windows 驗證。

下列範例顯示使用 SQL 驗證的 連接字串。 $CREDENTIAL_PLACEHOLDER$ 是密碼機碼/值組的佔位元。 請注意,認證會內嵌在 連接字串 中:

Server=serverName; Database=Northwind; uid=userID; $CREDENTIAL_PLACEHOLDER$

假設攻擊者能夠檢視您的應用程式 Web.config 檔案。 如果您使用 SQL 驗證連線到可透過因特網存取的資料庫,攻擊者可以使用此 連接字串 透過 SQL Management Studio 或從自己的網站上 ASP.NET 頁面連線到您的資料庫。 若要協助減輕此威脅,請使用受保護的組態系統加密 中的 Web.config 連接字串 資訊。

注意

如需 SQL Server 中可用之不同驗證類型的詳細資訊,請參閱建置安全 ASP.NET 應用程式:驗證、授權和安全通訊。 如需進一步 連接字串 說明 Windows 與 SQL 驗證語法差異的範例,請參閱 ConnectionStrings.com

摘要

根據預設,ASP.NET 應用程式中擴展名 .config 為的檔案無法透過瀏覽器存取。 這些類型的檔案不會傳回,因為它們可能包含敏感性資訊,例如資料庫連接字串、使用者名稱和密碼等等。 .NET 2.0 中的受保護組態系統可允許加密指定的組態區段,協助進一步保護敏感性資訊。 有兩個內建受保護的組態提供者:一個使用 RSA 演算法,另一個使用 Windows 數據保護 API (DPAPI) 。

在本教學課程中,我們已瞭解如何使用 DPAPI 提供者來加密和解密組態設定。 這可以透過程序設計方式完成,如我們在步驟 2 中所見,以及透過步驟 3 所涵蓋的 aspnet_regiis.exe 命令行工具來完成。 如需改用用戶層級密鑰或使用 RSA 提供者的詳細資訊,請參閱一節中的資源。

快樂的程序設計!

深入閱讀

如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Teresa Murphy 和 Randy Schmidt。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。