共用方式為


將密碼和其他敏感性資料部署到 ASP.NET 和 Azure App Service 的最佳做法

作者 :Rick Anderson

本教學課程說明您的程式代碼如何安全地儲存和存取安全資訊。 最重要的一點是,您不應該將密碼或其他敏感數據儲存在原始程式碼中,而且不應該在開發和測試模式中使用生產秘密。

此範例程式代碼是簡單的 WebJob 控制台應用程式和 ASP.NET MVC 應用程式,需要存取資料庫 連接字串 密碼、Twilio、Google 和 SendGrid 安全密鑰。

也提及內部部署設定和 PHP。

在開發環境中使用密碼

教學課程經常在原始程式碼中顯示敏感數據,希望您一律不要將敏感數據儲存在原始程式碼中。 例如,我的 ASP.NET MVC 5 應用程式與 SMS 和電子郵件 2FA 教學課程會在web.config檔案中顯示下列 內容

</connectionStrings>
   <appSettings>
      <add key="webpages:Version" value="3.0.0.0" />
      <!-- Markup removed for clarity. -->
      
      <!-- SendGrid-->
      <add key="mailAccount" value="account" />
      <add key="mailPassword" value="my password" />
      <!-- Twilio-->
      <add key="TwilioSid" value="My SID" />
      <add key="TwilioToken" value="My Token" />
      <add key="TwilioFromPhone" value="+12065551234" />

      <add key="GoogClientID" value="1234.apps.googleusercontent.com" />
      <add key="GoogClientSecret" value="My GCS" />
   </appSettings>
 <system.web>

web.config 檔案是原始程式碼,因此這些秘密不應儲存在該檔案中。 幸運的是, <appSettings> 元素具有屬性 file ,可讓您指定包含敏感性應用程式組態設定的外部檔案。 只要外部檔案未簽入來源樹狀結構,您就可以將所有秘密移至外部檔案。 例如,在下列標記中,檔案 AppSettingsSecrets.config 包含所有應用程式密碼:

</connectionStrings>
   <appSettings file="..\..\AppSettingsSecrets.config">      
      <add key="webpages:Version" value="3.0.0.0" />
      <add key="webpages:Enabled" value="false" />
      <add key="ClientValidationEnabled" value="true" />
      <add key="UnobtrusiveJavaScriptEnabled" value="true" />      
   </appSettings>
  <system.web>

此範例) (外部檔案中的標記AppSettingsSecrets.config ,是 web.config 檔案中找到的相同標記:

<appSettings>   
   <!-- SendGrid-->
   <add key="mailAccount" value="My mail account." />
   <add key="mailPassword" value="My mail password." />
   <!-- Twilio-->
   <add key="TwilioSid" value="My Twilio SID." />
   <add key="TwilioToken" value="My Twilio Token." />
   <add key="TwilioFromPhone" value="+12065551234" />

   <add key="GoogClientID" value="1.apps.googleusercontent.com" />
   <add key="GoogClientSecret" value="My Google client secret." />
</appSettings>

ASP.NET 運行時間會將外部檔案的內容與 appSettings> 專案中的<標記合併。 如果找不到指定的檔案,則執行階段會略過檔案屬性。

警告

安全性 - 請勿將 秘密 .config 檔案新增至專案,或將其簽入原始檔控制。 根據預設,Visual Studio 會將 Build Action 設定為 Content,這表示已部署檔案。 如需詳細資訊,請參閱 為什麼我的項目資料夾中的所有檔案都未部署? 雖然您可以對 秘密 .config 檔案使用任何擴充功能,但最好將其保留 .config,因為 IIS 不會提供配置檔。 另請注意, AppSettingsSecrets.config 檔案是 來自web.config 檔案的兩個目錄層級,因此完全不在解決方案目錄中。 藉由將檔案移出方案目錄,“git add *” 將不會將其新增至您的存放庫。

在開發環境中使用連接字串

Visual Studio 會建立使用 LocalDB 的新 ASP.NET 專案。 LocalDB 是專為開發環境所建立。 它不需要密碼,因此您不需要執行任何動作,以防止密碼簽入您的原始程式碼。 某些開發小組會使用需要密碼的完整版本 SQL Server (或其他 DBMS) 。

您可以使用 configSource 屬性來取代整個 <connectionStrings> 標記。 <appSettings>file不同於合併標記的屬性,屬性configSource會取代標記。 下列標記顯示 configSourceweb.config 檔案中的 屬性:

<connectionStrings configSource="ConnectionStrings.config">
</connectionStrings>

注意

如果您使用如上所示的屬性 configSource 將連接字串移至外部檔案,並讓 Visual Studio 建立新的網站,它將無法偵測您使用資料庫,而且當您從 Visual Studio 發佈至 Azure 時,將無法取得設定資料庫的選項。 如果您使用 configSource 屬性,您可以使用PowerShell來建立及部署您的網站和資料庫,也可以在發佈之前先在入口網站中建立網站和資料庫。

警告

安全性 - 不同於 AppSettingsSecrets.config 檔案,外部連接字串檔案必須位於與根 web.config 檔案相同的目錄中,因此您必須採取預防措施,以確保不會將它簽入來源存放庫。

注意

秘密檔案的安全性警告: 最佳做法是不要在測試和開發中使用生產秘密。 在測試或開發中使用生產密碼會洩漏這些秘密。

WebJobs 控制台應用程式

主控台應用程式所使用的 app.config 檔案不支持相對路徑,但支援絕對路徑。 您可以使用絕對路徑將秘密移出項目目錄。 下列標記顯示 C:\secrets\AppSettingsSecrets.config 檔案中的秘密,以及 app.config 檔案中的非敏感數據。

<configuration>
  <appSettings file="C:\secrets\AppSettingsSecrets.config">
    <add key="TwitterMaxThreads" value="24" />
    <add key="StackOverflowMaxThreads" value="24" />
    <add key="MaxDaysForPurge" value="30" />
  </appSettings>
</configuration>

將秘密部署至 Azure

當您將 Web 應用程式部署至 Azure 時, AppSettingsSecrets.config檔案將不會 部署 (您想要) 。 您可以移至 Azure 管理入口網站 並手動設定它們,以執行下列動作:

  1. 移至 https://portal.azure.com,然後使用您的 Azure 認證登入。
  2. 按兩下 [瀏覽>] Web Apps,然後按下 Web 應用程式的名稱。
  3. 按兩下 [所有設定 > ] [應用程式設定]。

應用程式設定連接字串 值會覆寫 web.config 檔案中的相同設定。 在我們的範例中,我們並未將這些設定部署到 Azure,但如果這些密鑰位於 web.config 檔案中,入口網站上顯示的設定會優先。

最佳做法是遵循 DevOps 工作流程並使用 Azure PowerShell ( 或其他架構,例如 ChefPuppet) ,在 Azure 中自動設定這些值。 下列 PowerShell 腳本會使用 Export-CliXml 將加密的秘密匯出至磁碟:

param(
  [Parameter(Mandatory=$true)] 
  [String]$Name,
  [Parameter(Mandatory=$true)]
  [String]$Password)

$credPath = $PSScriptRoot + '\' + $Name + ".credential"
$PWord = ConvertTo-SecureString –String $Password –AsPlainText -Force 
$Credential = New-Object –TypeName `
System.Management.Automation.PSCredential –ArgumentList $Name, $PWord
$Credential | Export-CliXml $credPath

在上述腳本中,'Name' 是秘密密鑰的名稱,例如 '“FB_AppSecret” 或 “TwitterSecret”。 您可以在瀏覽器中檢視腳本所建立的 「credential」 檔案。 下列代碼段會測試每個認證檔案,並設定具名 Web 應用程式的秘密:

Function GetPW_fromCredFile { Param( [String]$CredFile )
  $Credential = GetCredsFromFile $CredFile
  $PW = $Credential.GetNetworkCredential().Password  
  # $user just for debugging.
  $user = $Credential.GetNetworkCredential().username 
  Return $PW
}	
$AppSettings = @{	
  "FB_AppSecret"     = GetPW_fromCredFile "FB_AppSecret.credential";
  "GoogClientSecret" = GetPW_fromCredFile "GoogClientSecret.credential";
  "TwitterSecret"    = GetPW_fromCredFile "TwitterSecret.credential";
}
Set-AzureWebsite -Name $WebSiteName -AppSettings $AppSettings

警告

安全性 - 請勿在 PowerShell 腳本中包含密碼或其他秘密,這麼做會破壞使用 PowerShell 腳本來部署敏感數據的目的。 Get-Credential Cmdlet 提供安全的機制來取得密碼。 使用 UI 提示字元可防止密碼外洩。

部署 DB 連接字串

DB 連接字串的處理方式與應用程式設定類似。 如果您從 Visual Studio 部署 Web 應用程式,將會為您設定 連接字串。 您可以在入口網站中確認這一點。 使用 PowerShell 設定 連接字串 的建議方式。

PHP 附注

由於應用程式設定連接字串的索引鍵/值組都會儲存在 Azure App 服務 上的環境變數中,因此使用 PHP) 之類的任何 Web 應用程式架構 (的開發人員可以輕鬆地擷取這些值。 請參閱 Stefan Schackow 的 Windows Azure 網站:應用程式字串和連接字串的運作方式 部落格文章,其中顯示 PHP 代碼段來讀取應用程式設定和連接字元串。

內部部署伺服器的注意事項

如果您要部署至內部部署 Web 伺服器,您可以 加密組態檔的組態區段,以協助保護秘密。 或者,您可以使用 Azure 網站建議的相同方法:將開發設定保留在組態檔中,並使用環境變數值進行生產設定。 不過,在此情況下,您必須為 Azure 網站中自動的功能撰寫應用程式程式代碼:從環境變數擷取設定,並使用這些值來取代組態檔設定,或在找不到環境變數時使用組態檔設定。

其他資源

請參閱 Stefan Schackow 的 Windows Azure 網站:應用程式字串和連接字串的運作方式

特別感謝 Barry Dorrans ( @blowdart ) 和 Carlos Farre 進行檢閱。