一、 簡介
當創建ASP.NET 2.0應用程式時,開發者通常都會把敏感的設定資訊儲存在Web.config檔中。最典型的範例就是資料庫連接字串,但是包括在Web.config檔案中的其它敏感資訊還包括SMTP伺服器連接資訊和使用者憑證數據,等等。儘管預設可以設定ASP.NET以拒絕所有對副檔名為.config的檔案資源的HTTP請求;但是,如果一個駭客能夠存取你的web伺服器的檔案系統的話,那麼,Web.config中的敏感資訊仍然能夠被竊取。例如,也許你不小心允許匿名FTP訪問你的網站,這樣以來就允許一個駭客簡單地透過FTP協定下載你的Web.config檔。
幸好,透過允許加密Web.config檔案中選擇的部分,例如<connectionStrings>節,或你的應用程式使用的一些客製化config節,ASP.NET 2.0有助於緩解這個問題。配置部分能夠輕鬆地使用編碼或aspnet_regiis.exe(一個命令列程式)預先加密。一旦加密,Web.config設定即可避開"虎視眈眈"的眼睛。而且,當以程式設計方式從你的ASP.NET頁面中檢索加密的設定設定時,ASP.NET會自動地解密它讀取的加密部分。簡言之,一旦配置資訊被加密,你就不需要在你的應用程式中編寫任何其它程式碼或採取任何進一步的行為來使用該加密資料。
在本文中,我們將討論如何以程式設計方式加密和解密該組態設定部分,並且分析一下命令列程式aspnet_regiis.exe的使用。然後,我們將評估ASP.NET 2.0提供的加密選項。另外,也會簡短地討論如何加密ASP.NET版本1.x中的設定資訊。
二、 前提
在我們開始探討如何加密ASP.NET 2.0配置資訊之前,請記住下列幾點:
1. 所有形式的加密都會包含某種秘密,而當加密和解密資料時都要使用這一秘密。對稱加密演算法在加密和解密一個訊息時使用同一把金鑰,而非對稱加密演算法對於加密和解密卻使用不同的金鑰。無論使用哪種技術,最重要的還是看解密金鑰的安全保存程度。
2. ASP.NET 2.0提供的配置加密技術的設計目的在於,試圖阻止能夠以某種方式檢索你的設定檔的駭客的入侵。其實現思想是,如果在駭客的電腦上有你的Web.config檔;那麼,他不能破解該加密的部分。然而,當web伺服器上的一個ASP.NET頁面從一個加密的設定檔請求資訊時,該資料必須被解密才能使用(並且這時不需要你編寫任何程式碼)。因此,如果一個駭客能夠把一個能夠查詢設定檔並顯示它的結果的ASP.NET web頁面上傳到你的系統,那麼,他就能夠以普通文字方式觀看被加密的設定。 (詳細情況請參考本文提供的範例ASP.NET頁面,它展示了加密和解密Web.config檔案中各部分的方法;如你所見,一個ASP.NET頁面能夠存取(並顯示)該加密數據的普通文字形式)
3. 加密和解密配置資訊需要付出一定的效能代價。因此,通常是僅加密包含敏感資訊的配置部分。比如說,可能不需要加密<compilation>或<authorization>配置部分。
三、 加密何種資訊
在我們分析如何加密ASP.NET 2.0配置資訊前,讓我們先來看看能夠加密什麼組態資訊。使用.NET框架2.0提供的函式庫,開發人員能夠加密在Web.config或machine.config檔中的絕大多數的設定部分。這些配置部分是一些作為<configuration>或<system.web>元素子結點的XML元素。例如,下面的範例Web.config檔中含有三個組態設置,明確定義為:
<connectionStrings>,<compilation>和<authentication>。
<?xml version="1.0"?>
<configuration xmlns=" http://schemas.microsoft.com/.NetConfiguration/v2.0 ">
<connectionStrings>
<add name="MembershipConnectionString" connectionString="connectionString"/>
</connectionStrings>
<system.web>
<compilation debug="true"/>
<authentication mode="Forms" />
</system.web>
這些節中的每一個都可以選擇性地被加密,或者透過程式設計方式或透過aspnet_regiis.exe(一個命令列工具)實現。當加密時,加密後的文字直接儲存在設定檔中。例如,如果我們要加密上面的<connectionStrings>節,那麼結果Web.config檔案可能看起來如下所示:(注意:篇幅所限,我們省略了一大塊<CipherValue>)
<?xml version="1.0 "?>
<configuration xmlns=" http://schemas.microsoft.com/.NetConfiguration/v2.0 ">
<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAed...GicAlQ==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
<system.web>
<compilation debug="true"/>
<authentication mode="Forms" />
</system.web>
另外,存在一些你不能使用這個技術加密的配置部分:
· <processModel>
· <runtime>
· <mscorlib>
· <startup>
· <system.runtime.remoting>
· <configProtectedData>
· <satelliteassemblies>
· <cryptographySettings>
· <cryptoNameMapping>
· <cryptoClasses>
為了加密這些設定部分,你必須加密這些值並把它儲存在登錄中。存在一個aspnet_setreg.exe命令列工具可以幫助你實現這個過程;我們將在本文後面討論這個工具。
【提示】Web.Config和Machine.Config之區別:
Web.config檔案指定針對一個特定的web應用程式的設定設置,並且位於應用程式的根目錄下;而machine.config檔案指定所有的位於該web伺服器上的站點的配置設置,並且位於$WINDOWSDIR$Microsoft.NetFrameworkVersionCONFIG目錄下。
四、加密選項
開發人員可以使用ASP.NET 2.0提供者模型來保護配置節訊息,這允許任何實作都可以無縫地插入到該API中。 .NET架構2.0中提供了兩個內建的提供者用於保護設定節資訊:
· Windows資料保護API(DPAPI)提供者(DataProtectionConfigurationProvider):這個提供者使用Windows內建的密碼學技術來加解密組態節。預設情況下,這個提供者使用本機的金鑰。你還能夠使用用戶密鑰,但是這要求進行一點自訂。
· RSA保護的設定提供者(RSAProtectedConfigurationProvider):使用RSA公鑰加密來加解密組態節。使用這個提供程序,你需要建立儲存用於加解密配置資訊的公鑰和私鑰的金鑰容器。你能夠在一個多伺服器場所下使用RSA,這只要建立可輸出的金鑰容器即可。
當然,如果需要的話,你也能夠建立自己的保護設定提供者。
在本文中,我們僅討論使用DPAPI提供者使用機器級金鑰。到目前為止,這是最簡單的方法,因為它不要求建立任何金鑰或金鑰容器。當然,其消極的一面在於:一個加密的設定檔僅能夠用於首先實現加密的web伺服器上;而且,使用機器密鑰將允許加密的文本能夠被web伺服器上的任何網站所解密。
五、以程式方式加密配置部分
System.Configuration.SectionInformation類別對一個配置節的描述進行了抽象化。為了加密一個配置節,只需要簡單地使用SectionInformation類別的ProtectSection(提供者)方法,傳遞你想使用的提供者的名字來執行加密。為了存取你的應用程式的Web.config檔案中的一個特定的設定節,你可以使用WebConfigurationManager類別(在System.Web.Configuration命名空間中)來引用你的Web.config文件,然後使用它的GetSection (sectionName)方法傳回一個ConfigurationSection實例。最後,你可以經由ConfigurationSection實例的SectionInformation屬性得到一個SectionInformation物件。
下面,我們透過一個簡單的程式碼範例來說明問題:
privatevoid ProtectSection(string sectionName, string provider)
{
Configuration config = WebConfigurationManager.
OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.GetSection(sectionName);
if (section != null &&!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection(provider);
config.Save();
}
}
private void UnProtectSection(string sectionName) {
Configuration config =WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.GetSectio n(sectionName);
if (section != null && section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
config.Save();
}
你可以從一個ASP.NET頁面中呼叫這個ProtectSection(sectionName,provider)方法,其對應的參數是一個節名(如connectionStrings)和一個提供者(如DataProtectionConfigurationProvider),並且它打開Web.config文件,引用該節,呼叫SectionInformation物件的ProtectSection(provider)方法,最後儲存配置變更。
另一方面,UnProtectSection(provider)方法實作解密一個特定的配置節。在此,僅需要傳入要解密的節-我們不需要麻煩提供程序,因為該信息已經存儲在伴隨encrypted節的標記中(也即是,在上面的示例中的<connectionStrings>節,在被加密以後,它包含了提供者:<connectionStringsconfigProtectionProvider="DataProtectionConfigurationProvider">)。
記住,一旦該資料被加密,當從一個ASP.NET頁面讀取它時(也即是,從一個SqlDataSource控製或以編程方式經由ConfigurationManager.ConnectionStrings[connStringName].ConnectionString讀取該連接字串資訊) ,ASP.NET會自動地解密該連接字串並且傳回普通文字值。換句話說,實現加密後,你一點不需要改變你的程式碼。相當酷,對不對?
從本文下載的範例ASP.NET 2.0網站中,你會發現有一個範例頁面,它展示了該網站的Web.config文件,其中有一個多行TextBox,也提供了對應的Web控制按鈕用於加密配置文件的各個部分。這個範例中也使用了上面已經討論過的ProtectSection()和UnProtectSection()方法。
六、 使用命令列工具aspnet_regiis.exe
你還能夠使用aspnet_regiis.exe命令列工具來加密和解密Web.config檔設定部分,你可以在"%WINDOWSDIR%Microsoft.NetFrameworkversion"目錄下找到這個工具。為了加密Web.config檔案中的一個節,你可以在這個命令列工具中使用DPAPI機器金鑰,如下所示:
加密一個特定網站的Web.config檔的通用形式:
aspnet_regiis.exe -pef section physical_directory - prov provider
或:
aspnet_regiis.exe -pe section -app virtual_directory -prov provider
加密一個特定網站的Web.config檔的具體實例:
aspnet_regiis.exe -pef "connectionStrings" "C:InetpubwwwrootMySite" -prorootv " DataProtectionConfigurationProvider"
或:
aspnet_regiis.exe -pe "connectionStrings" -app "/MySite" -prov "DataProtectionConfigurationProvider"
解密一個特定網站的Web.config檔的通用形式:
aspnet_regiis.exe -pdf section physical_ditory檔案
的通用形式:
aspnet_regiis.exe
-pdf section physical_ditory.section -app virtual_directory
解密一個特定網站的Web.config檔的具體實例:
aspnet_regiis.exe -pdf "connectionStrings" "C:InetpubwwwrootMySite"
或:
你也能夠指定由aspnet_regiis.exe來執行machine.config文件的加密/解密。
【提示】 加密ASP.NET版本1.x中的配置設定
為了保護ASP.NET版本1.x中的配置設置,開發者需要加密並把敏感的設置存儲在web伺服器的註冊表中,並以一種"強"鍵方式儲存。設定檔中不是儲存加密的內容(如ASP.NET 2.0),而只是包含一個到儲存該加密值的註冊表鍵的參考。例如:
<identity impersonate="true"
userName="registry:HKLMSOFTWAREMY_SECURE_APPidentityASPNET_SETREG,userName"
password="registry:HKLMSOFTWAREMY_SECURE_APPidentityASPNET_SETREG,password" />
微軟為開發人員提供了aspnet_setreg.exe命令列工具,用於加密敏感的配置資訊並且把它移到一個"強"註冊表入口處。遺憾的是,這個工具僅針對特定的配置設定工作;相較之下,ASP.NET 2.0允許加密任何配置節。
有關在一個ASP.NET 1.x應用程式中使用aspnet_setreg.exe的更多資訊請參考MSDN中的KB#32990。遺憾的是,這個命令列程式只能加密配置設定中的預先定義的節,並且不允許你加密你自己添加的資料庫連接字串和其它敏感資訊。
七、 結論
在本文中,我們學習瞭如何使用ASP.NET 2.0提供的不同的加密選項來保護配置節信息,還討論瞭如何使用編程技術和aspnet_regiis.exe來分別加密Web.config中的配置節。保護你的敏感的配置設定有助於確保你的網站更難於被駭客攻擊-通過使其更難於發現敏感的配置設定。如今,ASP.NET 2.0已經提供了相對容易的加密和解密技術,開發者毫無理由不使用這種方式來保護你的敏感的配置設定。