天天看點

《ASP.NET本質論》 ASP.NET中的加密與解密

        在ASP.NET中設計兩個方面的加密和解密:一個是針對配置檔案中配置節的加密和解密,另外一個是針對ASP.NET中資料的加密和解密

        在 .NET 中,加密和解密的技術可以分為兩種。一種是加密和解密使用同樣的密鑰和算法,我們稱之為密鑰加密或者對稱加密,這個方法的特點是非常快。另外一種加密方式為公鑰加密或者成為非對稱加密,這種加密算法對于加密和解密使用不同的密鑰,通常有連個密鑰A和B,使用密鑰A加密資料得到密文,隻有密鑰B可以進行解碼操作;而使用密鑰B加密資料得到密文,隻有密鑰A可以解密。這兩個密鑰分别稱為四要和公鑰。非對稱加密強度大,但是處理速度比較慢。

       與此相關還有兩個概念:數字簽名和散列。公鑰算法還可用于構成數字簽名,用來驗證資訊發送方的身份(如果您信任發送方的密鑰)并幫助保護資料的完整性。雜湊演算法将任意長度的二進制值映射為固定長度的較小二進制值,這個小的二進制值成為散列之。散列函數來確定消息的完整性。

    machineKey

        在ASP.NET中的很多加密和解密都要依賴于密鑰,密鑰儲存在配置檔案的machineKey裡面。預設情況下,ASP.NET通過動态生成來建立網站所使用的密鑰,如果單台伺服器當然沒問題,但是如果網站采用多台伺服器負載均衡,machineKey還采用動态生成的方式,那麼,每台伺服器上的machineKey的值不一緻,會導緻加密出來的結果也不一緻,不能共享驗證和ViewState,是以對于多台伺服器負載均衡的情況,一定要在每台站點配置相同的machineKey。

        ASP.NET中,machineKey用于以下三種用途:

          使用 forms authentication時的cookie資料的加密和解密,以確定這部分資料不會被篡改。

          viewstate資料的加密和解密,以確定這部分資料不會被篡改。

          使用程序外session(out-of-process session)時,對話狀态辨別進行驗證。

        ASP.NET使用的密鑰儲存在配置檔案中,配置節machineKey用于設定加密和解密哦參數,代碼如下所示:

<machineKey 
   validationKey="AutoGenerate|value[,IsolateApps]"
   decryptionKey="AutoGenerate|value[,IsolateApps]"
   validation="[SHA1|MD5|3DES]"
   decryption="[Auto|]"
/>
           

http://msdn.microsoft.com/zh-cn/library/w8h3skw9(v=vs.80).aspx

        其中,AutoGenerate修飾符指定ASP.NET生成随機密鑰并将其存儲在本地安全機構(LSA)中。IsolateApps修飾符指定ASP.NEt使用應用程式ID為每個應用程式生成唯一的密鑰。IsolateApps作為一部分包含在預設值中。

        為了防止篡改ViewState,散列的消息驗證碼(HMAC)被用于ViewState,并在後繼的請求中用來比較檢查。這個操作使用machineKey配置參數中validataion設定的驗證算法,預設的驗證算法是SHA1,并使用validationKey作為驗證。

        對于敏感的頁面,通過設定頁面的ViewStateEncryptionMode="Always"來強制對頁面的ViewState進行加密。

        decryptionKey用來對資料進行加密和解密。例如,表單驗證、角色管理和匿名辨別都使用它來加密和解密資料,在validataion設定為AES或者3DES的時候,ASP.NET還用它來加密和解密ViewState資料。

        對于validataionKey來說,可以指定一個手動配置設定的密鑰。該值必須手動設定為十六進制字元串,以確定在整個網絡場中保持一緻。在使用AES加密時,密鑰長度必須為64位十六進制字元串;在使用MD5加密時,密鑰長度必須為32為十六進制字元串;使用SHA1加密時,密鑰長度必須為40位十六進制字元串;使用3DES時,密鑰長度必須為48位十六進制字元串;使用HMACSHA256時,使用長度為64位十六進制字元串;使用HMACSHA384時,使用長度為96位十六進制字元串;使用HMACSHA512時,使用長度為128位十六進制字元串。

        對于decryptionKey來說,可以指定一個手動配置設定的密鑰。該值必須手動設定為十六進制字元串,以確定配置在整個網絡場中保持一緻。使用DES加密時,密鑰長度應該為16位十六進制字元串;而使用三重DES(3DES)或AES加密時,密鑰長度應該為48位十六進制字元串。當使用AES時,密鑰長度可以是32個字元(128位),48個字元(192位),也可以是64個字元(256位)。首選項是使用64個字元,以便提供解密強度。

       使用RNGCryptoServiceProvider可以幫助我們建立比Random更加随機的随機數,RNGCryptoServiceProvider類産生的随機數更加随機,即使有人知道了這個類,并得到最生成的随機序列,也無法計算後續序列。這個類定義在命名空間System.Security.Cryptography中,定義如下:

           public seald class RNGCryptoServiceProvider:RandomNumberGenerator

        我們通常使用這個對象的GetBytes方法類獲得一組随機數,GetBytes會通過将随機數填充到我們通過參數傳遞的數組來建立随機數。

               public override void GetBytes( byte[] data) 

        例如,我們可以通過下面的方法來建立指定位元組的随機數:

public static string CreateKey(int len)
{
    byte[] bytes = new byte[len];
    RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
    provider.GetBytes(bytes);

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.Length; i++)
    {
        sb.Append(string.Format("{0:X2}", bytes[i]));
    }

    return sb.ToString();
}
           

    加密服務

        CSP(Cryptographic Sevice Provider,加密服務子產品)是一個真正執行加密功能的獨立子產品,典型的CSP有微弱RSA Base Provider。 CSP既可以由軟體實作也可以由硬體實作,但是必須符合CryptoAPI接口規範。

        每個CSP都有一個名字和一個類型。每個CSP的名字是唯一的,這樣便于CryptoAPI找到對應的CSP。每個CSP有一個密鑰庫,密鑰庫用于存儲密鑰。而每個密鑰包括一個或多個密鑰容器( Key Containers )。每個密鑰容器中包含屬于一個特定使用者的所有密鑰對,并被賦予一個唯一的名字。

        加密和解密XML格式的配置檔案需要設定一些RSA方面的知識。RsaProtectedConfigurationProvider類提供使用RSA加密對配置資料進行加密和解密,RSA使用密鑰容器來管理密鑰,RsaProtectedConfigurationProvider類可以使用計算機級别或使用者級别的RSA密鑰容器。Microsoft Windows 為所有使用者提供計算機級别的密鑰容器,而使用者級别的密鑰容器隻能供建立(或導入)了該密鑰容器的使用者使用。

        使用者級别的RSA密鑰容器存儲在特定使用者的Windows使用者配置檔案中,并且可以用于加密和解密在該特定使用者辨別下運作的應用程式的資訊。如果希望確定在移除Windows使用者配置檔案時同時移除RSA密鑰資訊,則使用者級别的RSA密鑰容器非常有用。但是,由于登入時必須使用特定的使用者帳戶(該賬戶将利用使用者級别的RSA密鑰勇氣來加密或解密受保護的配置節),是以他們使用起來不太友善。

        預設情況下,計算機級别的RSA密鑰容器對于所有可以登入到計算機的使用者都可用,而且由于使用管理者帳号登入時可以使用這些密鑰容器加密或解密受保護的配置節,是以他們是最有用的。計算機級别的RSA密鑰是容器可以用于為單個應用程式,一台伺服器上的所有應用程式或者伺服器上在同一使用者表示下運作的一組應用程式提供資訊保護。計算機級别的RSA密鑰容器對所有的使用者都可通路,不過也可以使用NTFS通路控制清單(ACL)保護這些密鑰容器,以便隻有需要的使用者才能通路它們。

         在.NET中可以比較友善地管理密鑰容器,定義在命名空間System.Sercurity.Cryptography中的RSACryptoServiceProvider和表示傳遞給執行加密計算的加密服務提供程式(CSP)的參數CspParameters可以用來建立和删除密鑰容器。

CspParameters cp = new CspParameters();
    cp.KeyContainerName = ContainerName;
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
           

        建立和讀取密鑰容器都使用上述代碼,如果密鑰容器不存在,則會自動建立,并将RSA産生的密鑰容器存入其中;如果已經存在,則會讀取其中的密鑰給RSA。

        删除密鑰容器使用RSACryptoServiceProvider的Clear方法完成。

CspParameters cp = new CspParameters();
    cp.KeyContainerName = ContainerName;
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
    rsa.PersistKeyInCsp = false;
    rsa.Clear();
           

    配置節的加密和解密

        在配置檔案的configProtectedData節中指定受保護配置提供程式。如果要使用自定義設定指定自己的提供程式,可以使用providers元素的add元素聲明新的提供程式執行個體。可以使用configProtectedData元素的defaultProvider特性将該提供程式執行個體表示為預設的提供程式。

       預設情況下,Machine.config檔案中指定了下列受保護配置提供程式。

      1)名為:RsaProtectedConfigurationProvider 的RsaProtectedConfigurationProvider執行個體。該提供程式配置為預設提供程式。

http://msdn.microsoft.com/zh-cn/library/system.configuration.rsaprotectedconfigurationprovider(VS.80).aspx

      2)名為 DataProtectionConfigurationProvider的DpapiProtectedConfigurationProvider執行個體

http://msdn.microsoft.com/zh-cn/library/system.configuration.dpapiprotectedconfigurationprovider(v=VS.80).aspx

</configSections>
	<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
		<providers>
			<add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="NetFrameworkConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/>
			<add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt" useMachineProtection="true" keyEntropy=""/>
		</providers>
	</configProtectedData>
           

        在ASP.NET中,預設使用 RsaProtectedConfigurationProvider 來加密存儲在配置檔案中的敏感資訊,防止對這些資訊進行為授權的通路。keyContainerName屬性指定了使用的密鑰容器,由于RsaProtectedConfigurationProvider需要通路密鑰容器來使用密鑰,是以,必須保證這個密鑰容器存在,并且目前的Windows使用者具有通路的權限。

      常見參數如下:

-pc 在指定密鑰容器中建立RSA公鑰/私鑰對。如果密鑰容器不存在,則建立密鑰容器。
-exp 參數指定可以導出私鑰。
-pz 删除指定的密鑰容器。
-px 将RSA公鑰/私鑰對從指定的容器導入指定的XML檔案。
-pi 将RSA公鑰/私鑰對從指定的XML file導入指定的容器。
-pe 加密配置節。
-pd 解密配置節。
-pef 加密實體目錄,非虛拟目錄中的web.config中的配置節。
-pdf 解密實體目錄,而非虛拟目錄中的web.config中的配置節。
-pa 未指定使用者或組account授予通路指定項container的權限。
-pr 移除指定的使用者或組account對指定的項container的通路權限。
-pri 可以在XML檔案中包括私鑰。

        例如,授予NT AUTHORITY\NETWORK SERVICE 使用者通路密鑰容器NetFramerworkConfigurationKey的全新.

                aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"

       如果自定義了密鑰容器,例如,通過下面的命名建立的新密鑰容器,希望在ASP.NET中使用。為確定可以導出新建立的RSA密鑰容器,必須包括 -exp選項。該容器是可導出的計算機級密鑰容器。

                aspnet_regiis -pc "MyConfigurationKey" -exp

       那麼,可以在配置檔案中如下設定所使用的密鑰容器。

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
		<providers>
			<add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="MyConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/>
			<add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt" useMachineProtection="true" keyEntropy=""/>
		</providers>
	</configProtectedData>
           

        可以将密鑰導出到XML檔案中。

                     aspnet_regiis -px "MyConfigurationKey" "MyConfigurationKey.xml"

       這個指令隻導出公鑰,是以以後隻能用于加密,而無法解密。使用pri參數之後,可以将私鑰一起導出。

                     aspnet_regiis -px "MyConfigurationKey"

                                               -pri "MyConfigurationKey.xml"

       删除密鑰容器

                    aspnet_regiis -pz "MyConfigurationKey"

       從XML檔案中導入密鑰容器

                   aspnet_regiis -pi "MyConfigurationKey" "MyConfigurationKey.xml" 

繼續閱讀