ASP.NET 및 Azure App Service에 암호와 기타 중요한 데이터를 배포하는 방법에 대한 모범 사례

작성자: Rick Anderson

이 자습서에서는 코드가 보안 정보를 안전하게 저장하고 액세스하는 방법을 보여줍니다. 가장 중요한 점은 암호 또는 기타 중요한 데이터를 소스 코드에 저장해서는 안 되며 개발 및 테스트 모드에서 프로덕션 비밀을 사용하면 안 된다는 것입니다.

샘플 코드는 간단한 WebJob 콘솔 앱이며 데이터베이스 연결 문자열 암호, Twilio, Google 및 SendGrid 보안 키에 액세스해야 하는 ASP.NET MVC 앱입니다.

온-프레미스 설정 및 PHP도 언급됩니다.

개발 환경에서 암호 작업

자습서에서는 소스 코드에 중요한 데이터를 저장해서는 안 된다는 주의 사항과 함께 중요한 데이터를 소스 코드에 자주 표시합니다. 예를 들어 SMS 및 이메일 2FA가 포함된 ASP.NET MVC 5 앱 자습서는 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 ActionContent설정합니다. 즉, 파일이 배포됩니다. 자세한 내용은 프로젝트 폴더의 모든 파일이 배포되지 않는 이유는 무엇인가요? 를 참조하세요. 비밀 .config 파일에 확장명은 사용할 수 있지만 구성 파일이 IIS에서 제공되지 않으므로 .config유지하는 것이 가장 좋습니다. 또한AppSettingsSecrets.config 파일은 web.config 파일에서 두 개의 디렉터리 수준이므로 솔루션 디렉터리에서 완전히 벗어났습니다. 솔루션 디렉터리에서 파일을 이동하면 "git add *"가 리포지토리에 추가되지 않습니다.

개발 환경에서 연결 문자열 작업

Visual Studio는 LocalDB를 사용하는 새 ASP.NET 프로젝트를 만듭니다. LocalDB는 개발 환경을 위해 특별히 만들어졌습니다. 암호가 필요하지 않으므로 비밀이 소스 코드에 체크 인되는 것을 방지하기 위해 아무 작업도 수행할 필요가 없습니다. 일부 개발 팀은 암호가 필요한 전체 버전의 SQL Server(또는 다른 DBMS)를 사용합니다.

특성을 사용하여 configSource 전체 <connectionStrings> 태그를 바꿀 수 있습니다. 태그를 <appSettings>file 병합하는 특성과 달리 특성은 configSource 태그를 대체합니다. 다음 태그는 web.config 파일의 특성을 보여 configSource 줍니다.

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

참고

위와 같이 특성을 사용하여 configSource 연결 문자열을 외부 파일로 이동하고 Visual Studio에서 새 웹 사이트를 만들면 데이터베이스를 사용하고 있음을 감지할 수 없으며 Visual Studio에서 Azure에 게시할 때 데이터베이스를 구성하는 옵션이 표시되지 않습니다. 특성을 사용하는 경우 PowerShell을 configSource 사용하여 웹 사이트 및 데이터베이스를 만들고 배포하거나 게시하기 전에 포털에서 웹 사이트와 데이터베이스를 만들 수 있습니다.

경고

보안 - 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에 비밀 배포

Azure에 웹앱을 배포하면 AppSettingsSecrets.config 파일이 배포되지 않습니다(원하는 내용). 이렇게 하려면 Azure 관리 포털로 이동하여 수동으로 설정할 수 있습니다.

  1. https://portal.azure.com이동하여 Azure 자격 증명으로 로그인합니다.
  2. Web Apps 찾아보기를 >클릭한 다음 웹앱의 이름을 클릭합니다.
  3. 모든 설정 > 애플리케이션 설정을 클릭합니다.

앱 설정연결 문자열 값은 web.config 파일에서 동일한 설정을 재정의합니다. 이 예제에서는 이러한 설정을 Azure에 배포하지 않았지만 이러한 키가 web.config 파일에 있는 경우 포털에 표시된 설정이 우선합니다.

모범 사례는 DevOps 워크플로를 따르고 Azure PowerShell(또는 Chef 또는 Puppet과 같은 다른 프레임워크)를 사용하여 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" 파일을 볼 수 있습니다. 아래 코드 조각은 각 자격 증명 파일을 테스트하고 명명된 웹앱에 대한 비밀을 설정합니다.

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에서 웹앱을 배포하는 경우 연결 문자열 구성됩니다. 포털에서 이를 확인할 수 있습니다. 연결 문자열 설정하는 권장 방법은 PowerShell을 사용하는 것입니다.

PHP에 대한 참고 사항

앱 설정연결 문자열 모두에 대한 키-값 쌍은 Azure App Service 환경 변수에 저장되므로 PHP와 같은 웹앱 프레임워크를 사용하는 개발자는 이러한 값을 쉽게 검색할 수 있습니다. 앱 설정 및 연결 문자열을 읽는 PHP 조각을 보여 주는 Stefan Schackow의 Windows Azure 웹 사이트: 애플리케이션 문자열 및 연결 문자열 작동 방법 블로그 게시물을 참조하세요.

온-프레미스 서버에 대한 참고 사항

온-프레미스 웹 서버에 배포하는 경우 구성 파일의 구성 섹션을 암호화하여 비밀을 보호할 수 있습니다. 또는 Azure Websites에 권장되는 동일한 접근 방식을 사용할 수 있습니다. 구성 파일에 개발 설정을 유지하고 프로덕션 설정에 환경 변수 값을 사용합니다. 그러나 이 경우 Azure Websites에서 자동으로 작동하는 기능에 대한 애플리케이션 코드를 작성해야 합니다. 환경 변수에서 설정을 검색하고 구성 파일 설정 대신 해당 값을 사용하거나 환경 변수를 찾을 수 없는 경우 구성 파일 설정을 사용해야 합니다.

추가 리소스

Stefan Schackow의 Windows Azure 웹 사이트: 애플리케이션 문자열 및 연결 문자열 작동 방식을 참조하세요.

검토를위한 배리 도란스 ( @blowdart )와 카를로스 파레에게 특별한 감사드립니다.