Compartilhar via


Melhores práticas para implantar senhas e outros dados confidenciais no ASP.NET e no Serviço de Aplicativo do Azure

por Rick Anderson

Este tutorial mostra como seu código pode armazenar e acessar informações seguras com segurança. O ponto mais importante é que você nunca deve armazenar senhas ou outros dados confidenciais no código-fonte e não deve usar segredos de produção no modo de desenvolvimento e teste.

O código de exemplo é um aplicativo de console WebJob simples e um aplicativo MVC ASP.NET que precisa de acesso a uma senha de string de conexão de banco de dados, chaves seguras Twilio, Google e SendGrid.

As configurações locais e o PHP também são mencionados.

Trabalhando com senhas no ambiente de desenvolvimento

Os tutoriais frequentemente mostram dados confidenciais no código-fonte, esperançosamente com uma ressalva de que você nunca deve armazenar dados confidenciais no código-fonte. Por exemplo, meu tutorial ASP.NET aplicativo MVC 5 com SMS e email 2FA mostra o seguinte no arquivo 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>

O arquivo web.config é o código-fonte, portanto, esses segredos nunca devem ser armazenados nesse arquivo. Felizmente, o <appSettings> elemento tem um file atributo que permite especificar um arquivo externo que contém configurações confidenciais do aplicativo. Você pode mover todos os seus segredos para um arquivo externo, desde que o arquivo externo não seja verificado em sua árvore de origem. Por exemplo, na marcação a seguir, o arquivo AppSettingsSecrets.config contém todos os segredos do aplicativo:

</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>

A marcação no arquivo externo (AppSettingsSecrets.config neste exemplo) é a mesma marcação encontrada no arquivo 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>

O runtime ASP.NET mescla o conteúdo do arquivo externo com a marcação no <elemento appSettings> . O runtime ignorará o atributo de arquivo se o arquivo especificado não puder ser encontrado.

Aviso

Segurança – não adicione seu arquivo .config de segredos ao seu projeto nem faça check-in no controle do código-fonte. Por padrão, o Visual Studio define o Build Action como Content, o que significa que o arquivo foi implantado. Para obter mais informações, consulte Por que nem todos os arquivos na pasta do meu projeto são implantados? Embora você possa usar qualquer extensão para o arquivo secrets .config, é melhor mantê-lo .config, pois os arquivos de configuração não são atendidos pelo IIS. Observe também que o arquivo AppSettingsSecrets.config está dois níveis de diretório acima do arquivo web.config , portanto, está completamente fora do diretório da solução. Ao mover o arquivo para fora do diretório da solução, "git add *" não o adicionará ao repositório.

Trabalhando com cadeias de conexão no ambiente de desenvolvimento

O Visual Studio cria novos projetos ASP.NET que usam o LocalDB. O LocalDB foi criado especificamente para o ambiente de desenvolvimento. Ele não requer uma senha, portanto, você não precisa fazer nada para impedir que os segredos sejam verificados em seu código-fonte. Algumas equipes de desenvolvimento usam as versões completas do SQL Server (ou outro DBMS) que exigem uma senha.

Você pode usar o configSource atributo para substituir toda <connectionStrings> a marcação. Ao contrário do <appSettings> file atributo que mescla a marcação, o configSource atributo substitui a marcação. A marcação a seguir mostra o configSource atributo no arquivo web.config :

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

Observação

Se você usar o atributo conforme mostrado acima para mover suas cadeias de conexão para um arquivo externo e fizer com que o configSource Visual Studio crie um novo site, ele não poderá detectar que você está usando um banco de dados e você não terá a opção de configurar o banco de dados ao publicar no Azure do Visual Studio. Se você estiver usando o atributo, poderá usar o configSource PowerShell para criar e implantar seu site e banco de dados ou poderá criar o site e o banco de dados no portal antes de publicar.

Aviso

Segurança – ao contrário do arquivo AppSettingsSecrets.config, o arquivo de cadeias de conexão externas deve estar no mesmo diretório que o arquivo web.config raiz, portanto, você terá que tomar precauções para garantir que não faça check-in no repositório de origem.

Observação

Aviso de segurança no arquivo de segredos: uma prática recomendada é não usar segredos de produção em teste e desenvolvimento. O uso de senhas de produção em teste ou desenvolvimento vaza esses segredos.

Aplicativos de console WebJobs

O arquivo app.config usado por um aplicativo de console não dá suporte a caminhos relativos, mas dá suporte a caminhos absolutos. Você pode usar um caminho absoluto para mover seus segredos para fora do diretório do projeto. A marcação a seguir mostra os segredos no arquivo C:\secrets\AppSettingsSecrets.config e dados não confidenciais no arquivo 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>

Implantando segredos no Azure

Quando você implanta seu aplicativo Web no Azure, o arquivo AppSettingsSecrets.config não será implantado (é isso que você deseja). Você pode acessar o Portal de Gerenciamento do Azure e defini-los manualmente para fazer isso:

  1. Vá para https://portal.azure.come entre com suas credenciais do Azure.
  2. Clique em Procurar > Aplicativos Web e clique no nome do seu aplicativo Web.
  3. Clique em Todas as configurações > Configurações do aplicativo.

As configurações do aplicativo e os valores da cadeia de conexão substituem as mesmas configurações no arquivo web.config. Em nosso exemplo, não implantamos essas configurações no Azure, mas se essas chaves estivessem no arquivo web.config , as configurações mostradas no portal teriam precedência.

Uma prática recomendada é seguir um fluxo de trabalho de DevOps e usar o Azure PowerShell (ou outra estrutura, como Chef ou Puppet) para automatizar a configuração desses valores no Azure. O script do PowerShell a seguir usa Export-CliXml para exportar os segredos criptografados para o disco:

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

No script acima, 'Name' é o nome da chave secreta, como '"FB_AppSecret" ou "TwitterSecret". Você pode visualizar o arquivo ".credential" criado pelo script em seu navegador. O snippet abaixo testa cada um dos arquivos de credencial e define os segredos para o aplicativo Web nomeado:

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

Aviso

Segurança – não inclua senhas ou outros segredos no script do PowerShell, isso anula a finalidade de usar um script do PowerShell para implantar dados confidenciais. O cmdlet Get-Credential fornece um mecanismo seguro para obter uma senha. O uso de um prompt de interface do usuário pode evitar o vazamento de uma senha.

Implantando cadeias de conexão de banco de dados

As cadeias de conexão do banco de dados são tratadas de forma semelhante às configurações do aplicativo. Se você implantar seu aplicativo Web do Visual Studio, a cadeia de conexão será configurada para você. Você pode verificar isso no portal. A maneira recomendada de definir a cadeia de conexão é com o PowerShell.

Notas para PHP

Como os pares de chave-valor para configurações de aplicativo e cadeias de conexão são armazenados em variáveis de ambiente no Serviço de Aplicativo do Azure, os desenvolvedores que usam qualquer estrutura de aplicativo Web (como PHP) podem recuperar facilmente esses valores. Consulte a postagem do blog Sites do Windows Azure de Stefan Schackow: como funcionam as cadeias de caracteres de aplicativo e as cadeias de conexão, que mostra um snippet de PHP para ler as configurações do aplicativo e as cadeias de conexão.

Observações para servidores locais

Se você estiver implantando em servidores Web locais, poderá ajudar a proteger segredos criptografando as seções de configuração dos arquivos de configuração. Como alternativa, você pode usar a mesma abordagem recomendada para sites do Azure: manter as configurações de desenvolvimento em arquivos de configuração e usar valores de variáveis de ambiente para configurações de produção. Nesse caso, no entanto, você precisa escrever o código do aplicativo para a funcionalidade que é automática nos sites do Azure: recuperar configurações de variáveis de ambiente e usar esses valores no lugar das configurações do arquivo de configuração ou usar as configurações do arquivo de configuração quando as variáveis de ambiente não forem encontradas.

Recursos adicionais

Consulte os sites do Windows Azure de Stefan Schackow: Como funcionam as cadeias de caracteres de aplicativo e as cadeias de conexão

Agradecimentos especiais a Barry Dorrans ( @blowdart ) e Carlos Farre pela revisão.