[ASP.NET] 使用相同 RSA 金鑰容器幫 web.config 連線字串加密

使用 aspnet_regiis 將 web.config 內敏感的資料庫連線字串加密

前言

在開發初期可能不太有人會在連線字串加密議題上打轉,但隨著系統開發進入一個段落,資訊安全的議題就會被放大檢視了,因此對於 web.config 中敏感的連線字串肯定是需要被加密,避免資料庫連線方式被輕易地獲得。針對加密的方式可以選擇自行實作加解密的功能,但就必需要去介入取用連線字串的流程,確保加密後的連線字串可以正常解密取用,而好處就是都是自己實作,想要怎麼做就怎麼做,沒有太多的限制;另外可以考慮微軟提供的加解密方式,如此就不需要特別因為連線字串的加解密功能而調整程式碼,當然越方便的東西限制就可能比較多,因此本篇將針對此方式進行實作。

 

環境

  • IIS v7.5.7600.16385
  • Framework v4.0.30319

 

測試專案

首先建立一個測試專案,加入2組測試用 Connection String 於 Web.config 中,如下所示

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!--前略-->

  <!--連線字串-->
  <connectionStrings>

    <add name="BooDB1" 
         connectionString="Data Source=BooDB1; persist security info=True; initial catalog= Boo; user id=chris;password=bbbb1" 
         providerName="System.Data.SqlClient" />
    
    <add name="BooDB2" 
         connectionString="Data Source=BooDB2; persist security info=True; initial catalog= Boo; user id=chris;password=bbbb2" 
         providerName="System.Data.SqlClient" />
    
  </connectionStrings>
  
  <!--後略-->

</configuration>

然後在 Controller 中取出該些連線字串,存入 ViewBag 中

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.ConnStr1 = ConfigurationManager.ConnectionStrings["BooDB1"].ConnectionString;
        ViewBag.ConnStr2 = ConfigurationManager.ConnectionStrings["BooDB2"].ConnectionString;

        return View();
    }
}

在畫面上顯示剛取出的 ConnectionStrings 來驗證結果是否正確 

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>Connection String</h1>
    <p>@ViewBag.ConnStr1</p>
    <p>@ViewBag.ConnStr2</p>
</div>

執行後連線字串順利取出,後續將以此作為測試依據。

 

實作說明

微軟的加密功能會透過 aspnet_regiis.exe 工具來執行,而在介紹加解密方式之前有一件事情一定要知道,就是執行加解密時,預設會使用執行當下的電腦設備之所屬金鑰進行,亦表示若將此加密後的資料佈署到其他電腦時,是無法順利於其他電腦進行解密取得正確資訊,因此需要特別注意加解密執行位置。

以筆者電腦環境為例,可以從以下相對位置找到 aspnet_regiis.exe 工具,因此請先切換至此路徑中。 

C:\Windows\Microsoft.NET\Framework\v4.0.30319

 

使用預設RSA金鑰加密

針對單一網站伺服器,如果需要進行web.config加解密,最簡單的方式就是直接在該伺服器中,使用預設RSA金鑰來執行加解密動作。以下介紹如何利用 aspnet_regiis.exe 針對 web.config 進行加解密。

執行加密

語法: aspnet_regiis.exe -pef connectionStrings "D:\EncryptConfigWebAppTester\EncryptConfigWebAppTester"

執行以上語法後,就會直接將 D:\EncryptConfigWebAppTester\EncryptConfigWebAppTester 中的 Web.config 檔案針對 ConnectionStrings 區塊進行加密。

加密後 Web.config 中 ConnectionStrings 區塊就被加密了

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!--前略-->

  <!--連線字串-->
  <connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
      xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
            <CipherValue>qk4npNH9ehz1m7bXQXVWJLyjN7764d9/HYsdMcKquzz4T4dlHaqG05gSAfSdoytqUatxCU5Q5JpF/C4DxfPEx5y5AJi9e6RruJk+EEOEAsEStHne3b+3T672eXC7vAptxY0PAj6RexBiPOzmLYfpVDvFxfnlCDFC1Djl6o/Gzrk=</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>GRlZuh2BYgMhX8PqMSARFtX2lRMFB7QRItc+K1hk/p8wuFRV/aBd9PSIiSwaXOf5Ham0H63jHTk8piFce980Gy5WZtOhosJsUPf4UzfvLhHOBnyMZAAMZ5eLFhaqC9pnGsjC9cfQYXnNHrWKwJkHS0WQ36S1EMbUMLJYP0BmcdlQIrZPxuKfsWyWltGMDaXFNoZkY/RjeYIwdvPydnQ/aHdqCaxO5AB2C/GN43mcNT3sD0V+RXxjvRNzkiG0DRW+LqvX2XdWD/W3pSihbxYXjBPLfklOZ/Mz70pofj795cNKICI7qk3955Em0nsSpI0hVwB8k0roVQyx0FpdUgx2BHJv6a24yFO/3qUlr4q67BLXgRMldB0X2ts0yvmCwmUMO/7s/WoW708qIW67mSlEhXYUX2jW7SSfyCXNxkHBTyfXLHiJQGXyWT8KojBDyvrsqAcvkYie0rzr4o3dl9i1W+5c9lMfWOei8GD3AuXbbsvqsQzQiDoN9ATx/Lc6vDc0ZcREDs+I45Vd9cuGJN2fsas79zXaKfo6molD+0TMjVs=</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>
  
  <!--後略-->

</configuration>

接著什麼程式都不用修改,直接執行看看;結果確實可以將加密後的連線字串取出。

 

執行解密

語法: aspnet_regiis.exe -pdf connectionStrings "D:\EncryptConfigWebAppTester\EncryptConfigWebAppTester"

有加密就一定要解密;請執行以上語法,直接將 D:\EncryptConfigWebAppTester\EncryptConfigWebAppTester 中的 Web.config 檔案針對 ConnectionStrings 區塊進行解密。

Web.config 又恢復原始的面貌了

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!--前略-->

  <!--連線字串-->
  <connectionStrings>

    <add name="BooDB1" 
         connectionString="Data Source=BooDB1; persist security info=True; initial catalog= Boo; user id=chris;password=bbbb1" 
         providerName="System.Data.SqlClient" />
    
    <add name="BooDB2" 
         connectionString="Data Source=BooDB2; persist security info=True; initial catalog= Boo; user id=chris;password=bbbb2" 
         providerName="System.Data.SqlClient" />
    
  </connectionStrings>
  
  <!--後略-->

</configuration>

 

使用相同RSA金鑰加密

筆者先前有提到,加解密預設會使用"當前電腦"中的金鑰進行,如果希望讓所有伺服器都使用相同金鑰進行加解密動作,我們可以先在任一電腦預先建立RSA金鑰容器(Key Container),然後讓其他所有伺服器匯入此金鑰容器,如此就可以讓大家的加解密邏輯(金鑰)一致,詳細步驟請參考以下方式。

Setp 1. 建立共用 RSA 金鑰容器

語法: aspnet_regiis.exe -pc "ChrisKeys" -exp

建立名稱為 ChrisKeys 金鑰容器,並設定允許被匯出。

 

Setp 2. 在 Web.config 中加註ConfigProtectedData區塊

增加名稱為 ChrisProtectedProvider 的 RsaProtectedConfigurationProvider ,並指定使用先前建立名為 ChrisKeys 的電腦層級 RSA 金鑰容器。

<configProtectedData>
	<providers>
		<add name="ChrisProtectedProvider"
		type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
		keyContainerName="ChrisKeys"
		useMachineContainer="true" />
	</providers>
</configProtectedData>

 

Setp 3. 使用 ChrisProtectedProvider 來針對 Web.config 中的 ConnectionStrings 加密

語法: aspnet_regiis.exe -pef connectionStrings "D:\EncryptConfigWebAppTester\EncryptConfigWebAppTester" -prov "ChrisProtectedProvider"

加密後Web.config結果如下

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!--前略-->

  <!--Custom Provider-->
  <configProtectedData>
    <providers>
      <add name="ChrisProtectedProvider"
      type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
      keyContainerName="ChrisKeys"
      useMachineContainer="true" />
    </providers>
  </configProtectedData>
  
  <!--連線字串-->
  <connectionStrings configProtectionProvider="ChrisProtectedProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
      xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
            <CipherValue>kQJ07W23P05CCGusfLkPPeXuRbjD14Wn+8VzqKEQ/tcRbYzZjA1Pwi0QpZ8/p4trXQJw1jfDHS6VmsQTl+3h6GAGqWBWNcaZDS2zCePHw+JJwid8SiQZHrjoBPtN/y4boBtURhBcA0gLcuuMPLc7Ed8h931YkJ6R/+bHSLFB744=</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>4rhfEQ6lAJ8G/ER2l0FsEY1MqPquFXKAF0EbV+2gHAIznf0tOZQToVSQ4xNIB33KVzagzmqJP5uSAIWR1Gj3mB3J2JG2FcbIwVauhOQzCk1do3gDLDz8GPNABtxi0D0uSlbeLdLV57tk8EjCkdCDlX5cihR5HNWCQuAgiUgKfDOL2BfvBMYp52Nsbj2ZlC0cd3gefSVO/hiVp5+Oj7oYw7tvVl44YFV9jJtiexuavucEDswUuE+G/z8USD8EN8rMZVHxUdfpmLstF4WojPaYcAM3sITunIUqr0l8dbu+Ahulad/RIcyYIRM5bSPfZdC8TfaUN6ewJ/YazCRVCXOIguFhdf0wy0yhbWbSnqOlc9hiWkkB0ceYbP8MLTZEPcUwqtPCN5zyRBtVqQWU+4908cYhFlaXmfmbRy7jR4pxkH/p9y5pDwUe/sLRgog1P7pxsCtHAjll32njyf8YClIeuVT/Yp1j0ihnmrenAnhxgwuKSq/pFY+zTyNg99+j74ZozACwL+xWzrxpxgfpVV0ojJdpLvdhFnPGTIrZ7gjTXOo=</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>
  
  <!--後略-->

</configuration>

直接執行,確實可以將加密後的連線字串取出。

 

Setp 4. 把 RSA 金鑰容器匯出 (給其他伺服器使用)

語法: aspnet_regiis.exe -px “ChrisKeys” D:\ChrisKeys.xml -pri

 

Setp 5. 在其他伺服器將 RSA 金鑰容器匯入

語法: aspnet_regiis.exe -pi “ChrisKeys” D:\ChrisKeys.xml

 

Setp 6. 把相同程式連同加密後web.config複製至該伺服器中,直接執行程式。(正確讀出)

 

Setp 7. 模擬一下佈署上IIS的情況

首先把 使用 IIS Express 取消,並建立虛擬目錄。

執行程式,錯誤發生,無法開啟剛剛匯入的RSA金鑰容器 (權限問題)

來看一下IIS設定,此測試網站是使用 DefaultAppPool 應用程式集區,後續將針對此集區賦予權限。

 

Setp 8. 賦予帳戶 IIS AppPool\DefaultAppPool 權限來使用 ChrisKeys 金鑰容器

語法: aspnet_regiis.exe -pa “ChrisKeys” "IIS AppPool\DefaultAppPool"

執行下去,燈燈,成功了

 

參考資訊

http://www.codeproject.com/Articles/877258/How-to-Encrypt-Web-config-Using-aspnet-regiis-exe

http://blog.darkthread.net/post-2010-08-29-web-config-connstr-encryptor-v09-cht.aspx

http://blog.kkbruce.net/2008/09/aspnetwebconfig.html#.VnuZSnF974Y

http://blog.miniasp.com/post/2009/09/09/Introduce-IIS-75-Application-Pool-Identity-and-Virtual-Account.aspx


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !