Criando Web.Config Seguros com ProtectedConfigurationProvider

15 jun

Hoje irei demostrar como podemos criar arquivos de configuração criptografado para as nossas aplicações ASP.NET. Isso é muito importante dado que quando colocamos uma aplicação em produção não pensamos em proteger dados sensíveis deste arquivo, como uma conexão com o banco de dados por exemplo.

Essa técnica visa proteger nosso Web.Config dado que nosso servidor é passível de ataque pelo simples de estar na Internet.

Lembre-se a Internet é terra de ninguém então toda a preocupação com segurança é sempre válida.

Caso nosso servidor seja invadido, o hacker terá que quebrar a criptografia do nosso Web.Config para saber o acesso ao banco de dados por exemplo, isso torna a vida dele um pouco mais complicada não acham ?

No .NET para proteger nosso Web.Config usaremos a classe ProtectedConfigurationProvider.

Essa classe é responsável por criptografar e descriptografar nosso Web.Config. Para nós desenvolvedores isso é transparente dado que não precisamos nos preocupar em descriptografar chaves em Runtime. Ele faz todo o trabalho para a gente!

Vamos ao código =]

Criando o Custom Protected Configuration Provider

Para esse exemplo estarei usando a criptografia TripleDES, ele será o responsável por criptografar e descriptografar o nosso Web.Config tornando o processo transparente para a nossa aplicação.

Vamos criar um projeto do tipo Class Library chamado CriptoProtectedConfigurationProvider conforme imagem abaixo.

cripto

Esse será a biblioteca que ira criar nosso Web.Config criptografados.

Vamos adicionar uma nova classe chamada TripleDESProtectedConfigurationProvider, essa classe irá herdar de ProtectedConfigurationProvider.

A classe ProtectedConfigurationProvider é uma classe abstrata então devemos implementar seus métodos obrigatórios que são Decrypt e o Encrypt

public class TripleDESProtectedConfigurationProvider : ProtectedConfigurationProvider
   {
       private TripleDESCryptoServiceProvider tripleDesCripto = new TripleDESCryptoServiceProvider();
       private string key = "Sgo0k8dv112TCU0BiMNOo0tfR5AYmXeC";
       private string IV = "mmVbNIIj8k4=";

       public TripleDESProtectedConfigurationProvider()
       {
           //Lê a chave e o IV
           tripleDesCripto.Key = Convert.FromBase64String(key);
           tripleDesCripto.IV = Convert.FromBase64String(IV);
           //ECB(Electronic code Book)

           tripleDesCripto.Mode = CipherMode.ECB;
           //padding mode se tiver qualquer byte adicional a ser adicionado
           tripleDesCripto.Padding = PaddingMode.PKCS7;
       }


       public override XmlNode Encrypt(XmlNode node)
       {

           string encryptedData = EncryptString(node.OuterXml);

           //Cria a seção ou o Web Config Criptografado
           XmlDocument xmlDoc = new XmlDocument();
           xmlDoc.PreserveWhitespace = true;
           xmlDoc.LoadXml("<EncryptedData>" +  encryptedData + "</EncryptedData>");
           return xmlDoc.DocumentElement;
       }


       public override XmlNode Decrypt(XmlNode encryptedNode)
       {
           string decryptedData = DecryptString(encryptedNode.InnerText);

           //Descriptografa a seção ou o Web Config Criptografado
           XmlDocument xmlDoc = new XmlDocument();
           xmlDoc.PreserveWhitespace = true;
           xmlDoc.LoadXml(decryptedData);

           return xmlDoc.DocumentElement;
       }

       /// <summary>
       /// Metodo para Criptografar
       /// </summary>
       private string EncryptString(string encryptValue)
       {
           
           byte[] valBytes = Encoding.Unicode.GetBytes(encryptValue);

           ICryptoTransform transform = tripleDesCripto.CreateEncryptor();

           MemoryStream ms = new MemoryStream();
           CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write);
           cs.Write(valBytes, 0, valBytes.Length);
           cs.FlushFinalBlock();

           byte[] returnBytes = ms.ToArray();
           cs.Close();

           return Convert.ToBase64String(returnBytes);
       }

       /// <summary>
       /// Metodo para Descriptografar
       /// </summary>
       private string DecryptString(string encryptedValue)
       {
           byte[] valBytes = Convert.FromBase64String(encryptedValue);

           ICryptoTransform transform = tripleDesCripto.CreateDecryptor();

           MemoryStream ms = new MemoryStream();
           CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write);
           cs.Write(valBytes, 0, valBytes.Length);
           cs.FlushFinalBlock();
           byte[] returnBytes = ms.ToArray();
           cs.Close();

           return Encoding.Unicode.GetString(returnBytes);
       }

   }

 

Com a classe de TripleDESProtectedConfigurationProvider criada estamos aptos a proteger nossos arquivos de configuração.

Criando o Programa para criptografar o Web.Config

Com a classe TripleDESProtectedConfigurationProvider criada vamos criar um programa Console Application que irá receber o caminho do Web.Config e irá criptografar a ConnectionStrings.

Esse programa irá fazer

  1. Adicionar o nó configProtectedData, ele é responsável por entender qual classe será usada para criptografar e descriptografar o Web.Config. 
  2. Criptografar o nó connectionStrings 
  3. Salvar o Web.Config alterado
using CriptoProtectedConfigurationProvider;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace CriptoConsole
{
    class Program
    {
        static TripleDESProtectedConfigurationProvider provider = new TripleDESProtectedConfigurationProvider();

        static void Main(string[] args)
        {
            

            var path = String.Empty;
            while (String.IsNullOrEmpty(path))
            {
                Console.WriteLine("Selecione o caminho do Web.config");
                path = Console.ReadLine();
            }

            ProtectedConfiguration(path);
            Console.WriteLine("Web Config criptografado com sucesso");

            Console.Read();
        }

        private static void ProtectedConfiguration(string path)
        {

            XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(path);

            //Cria a seção criptografada
            var xmlContent = @"<configProtectedData><providers><add name='TripleDESProtectedConfigurationProvider' type='CriptoProtectedConfigurationProvider.TripleDESProtectedConfigurationProvider, CriptoProtectedConfigurationProvider' /></providers></configProtectedData>";

            XElement element = XDocument.Parse(xmlContent).Root;

            var xmlProtected = new XmlDocument();
            xmlProtected.LoadXml(element.ToString());
            var nodeProtected = xmlProtected.FirstChild;

            XmlNode nodeConfiguration = doc.SelectSingleNode("/configuration");
            var importNodeProvider = doc.ImportNode(nodeProtected, true);
            nodeConfiguration.InsertAfter(importNodeProvider, nodeConfiguration.FirstChild);


            // Pega a seção que será criptografada
            XmlNode node = doc.SelectSingleNode("/configuration/connectionStrings");

            //Encripta os dados do nó
            var criptoNode = provider.Encrypt(node);

            //Deleta todos os childs nodes e attributos
            node.RemoveAll();

            //Importa o no criptografado
            var importNodeCripto = doc.ImportNode(criptoNode, true);

            //Insere no nó de connection string
            node.InsertAfter(importNodeCripto, node.FirstChild);


            //Insere o atributo referencia para o configuration provider
            XmlAttribute attr = doc.CreateAttribute("configProtectionProvider");
            attr.Value = "TripleDESProtectedConfigurationProvider";
            node.Attributes.Append(attr);

            doc.Save(path);
        }
    }
}

Obs: Não se esqueça de referenciar a Class Library CriptoProtectedConfigurationProvider

Para finalizar nossa demostração, vou adicionar um projeto ASP.NET MVC conforme figura abaixo:

cripto3

Ao executar nosso programa irei passar o caminho do Web.Config do Projeto MVC recém criado

cripto4

Com o programa executado, iremos obter a seção connectionStrings criptografada conforme mostrada na figura abaixo:

<configProtectedData>
   <providers>
     <add name="TripleDESProtectedConfigurationProvider" type="CriptoProtectedConfigurationProvider.TripleDESProtectedConfigurationProvider, CriptoProtectedConfigurationProvider" />
   </providers>
 </configProtectedData>
 <connectionStrings configProtectionProvider="TripleDESProtectedConfigurationProvider">
   <EncryptedData>1DqQZqnecXHkkjpwUsI76WZz1tVO7sSMq7Mm8BDF1Ml2k1t++0cScYBukYqsBll7zLLSGBTYV+49u+S5F6ZcPI+2sDOun9yztHhbofAIRbTkkjpwUsI76Wim+y6z6Bj94V60cWoFP80HD8UeUVzhpla8AIUonpCpqEdHKIuVCTybTqmuvYLmDyCrbDsqB7ycs2ovMKLSU8Y+iPjkjLq7i9nG5R+OPRuutn4C79SBGtDYb/nvLDzKI4mGCWui9j1PoJoT0RvkJ14pRyEpXgWhH9tM6/v6+Q4DUiU4Gaax9bdyQQVvu+okKlOqCCfCsEPL7wjtPzRC3CW2lR3dynRvSJvu/clSSL560u2qVmJITD04D4vld8N+YnKrqk4DKc599Kh9o34+9POnwR3wrAnyc5K5zg02purfN2imnzA+w0V/GnrCIbRfkqIGP4TRg4E20jqMbn3mSNFZkqpzSu4EofACRZeev5nEYCwH8Assn7HxlnvPctAowHWJwr7fNXajS54X13+eNV91YUy6BsnI/q7UU15cV75IEZnP+W13xQnvNl60MNSZ2MT27Ot2Adj3jJdV/InSxcUuhaH1LmP/JFrU0IpvxOrnWOC+E+gjZlRlDFl/Z34SlQ==</EncryptedData>
 </connectionStrings>

Note no nó configProtectedData, ele está fazendo referencia a nossa biblioteca de criptografia de arquivos de configuração.

Agora basta executar nossa aplicação e deveremos obter a conectionStrings descriptografada pelo nosso componente de forma transparente conforme mostrado na figura abaixo.

cripto5

Obs: Não se esqueça de referenciar o projeto CriptoProtectedConfigurationProvider

Nossa aplicação funcionando normalmente com o Web.Config criptografado.

cripto6

Assim chegamos ao fim do post, com essa técnica podemos criptografar nosso Web.Config, aumentando a segurança de nossas aplicações e não complicando a vida dos desenvolvedores já que todo o processo é bem transparente.

Na verdade, nós desenvolvedores ao subir uma aplicação para produção, o pessoal de infraestrutura pode utilizar um programa parecido que demonstramos para criptografar o Web.Config.

O código desenvolvido não é afetado pelo processo de criptografia assim nossa aplicação fica mais segura, nós desenvolvedores não precisamos nos preocupar em fazer alteração no nosso código e todos ficam felizes =]

Espero que tenham gostado deste post e não deixem de comentar!

O código deste post está no GiutHub através deste link

Abs e até a próxima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *