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.
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
- Adicionar o nó configProtectedData, ele é responsável por entender qual classe será usada para criptografar e descriptografar o Web.Config.
- Criptografar o nó connectionStrings
- 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:
Ao executar nosso programa irei passar o caminho do Web.Config do Projeto MVC recém criado
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.
Obs: Não se esqueça de referenciar o projeto CriptoProtectedConfigurationProvider
Nossa aplicação funcionando normalmente com o Web.Config criptografado.
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
Não entendi como que aconteceu a descriptografia da conexão, onde acontece? Na aplicação Web ou na aplicação que criptografou?
Olá Marxed,
A descriptografia acontece na aplicação web. A própria aplicação web descriptografa para você de forma automática já que herdamos da classe ProtectedConfigurationProvider
Obrigado pela visita
Abs