Antecedentes
Tengo la tarea de configurar CI. Se decidió utilizar la transformación de los archivos de configuración y almacenar datos confidenciales en forma cifrada. Puede encriptarlos y desencriptarlos utilizando Key Container.
Contenedor clave
Cada sistema operativo Windows tiene conjuntos de claves generadas. La clave se genera en la cuenta o en la máquina. Las claves generadas por la máquina se pueden ver a lo largo de esta ruta C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys. Aquí es donde irá la clave que crearemos a continuación.
Creación de claves
Comenzamos cmd desde el administrador y cambiamos al directorio con aspnet_regiis, tengo este C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319
Ejecutar el comando
aspnet_regiis -pc "TestKey" -exp
exp: se agrega para que pueda exportar la clave en el futuro
TestKey: el nombre de nuestro contenedor de claves
Exportación clave
El equipo
aspnet_regiis -px "TestKey" :\TestKey.xml -pri
TestKey - nombre del contenedor de claves
C: \ TestKey.xml: la ruta donde se exportará el archivo
pri: agrega una clave privada para exportar
Clave de importación
El equipo
aspnet_regiis -pi "TestKey" :\TestKey.xml
TestKey - nombre del contenedor de claves
C: \ TestKey.xml: la ruta desde donde se exportará el archivo
Establecer derechos
Para que su aplicación o IIS funcione con el contenedor de claves, debe configurar los derechos para ello.
Esto lo hace el equipo
aspnet_regiis -pa "TestKey" "NT AUTHORITY\NETWORK SERVICE"
TestKey - nombre del contenedor de claves
NT AUTHORITY \ NETWORK SERVICE: quién tendrá acceso a la clave
De manera predeterminada, IIS tiene ApplicationPoolIdentity para el grupo.
La documentación de Microsoft (ver enlace 2) describe ApplicationPoolIdentity como:
ApplicationPoolIdentity : cuando se crea un nuevo grupo de aplicaciones, IIS crea una cuenta virtual que tiene el nombre del nuevo grupo de aplicaciones y que ejecuta el proceso de trabajo del grupo de aplicaciones en esta cuenta. Esta es también una cuenta menos privilegiada.
Por lo tanto, para que IIS pueda descifrar la configuración, Identity debe configurarse en el grupo para la cuenta, o puede seleccionar "SERVICIO DE RED" y otorgarle derechos.
Agregar una sección a la configuración
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="CustomRsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="TestKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/> </providers> </configProtectedData>
También el contenedor de claves y RsaProtectedConfigurationProvider se definen globalmente en archivos
C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Config \ machine.config, C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ Config \ machine.config
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="NetFrameworkConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/> <add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt" useMachineProtection="true" keyEntropy=""/> </providers> </configProtectedData>
Cifrado
El cifrado en sí se puede hacer de tres maneras.
Cifrado de línea de comando
aspnet_regiis.exe -pef connectionStrings :\Site -prov "CustomRsaProtectedConfigurationProvider"
C: \ Site: ruta al archivo con la configuración.
CustomRsaProtectedConfigurationProvider: nuestro proveedor especificado en la configuración llamada contenedor de claves.
Cifrado a través de una aplicación escrita.
private static string provider = "CustomRsaProtectedConfigurationProvider"; public static void ProtectConfiguration() { Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); ConfigurationSection connStrings = config.ConnectionStrings; if (connStrings != null && !connStrings.SectionInformation.IsProtected && !connStrings.ElementInformation.IsLocked) { connStrings.SectionInformation.ProtectSection(provider); connStrings.SectionInformation.ForceSave = true; config.Save(ConfigurationSaveMode.Full); } } public static void UnProtectConfiguration(string path) { Configuration config = ConfigurationManager.OpenExeConfiguration(path); ConfigurationSection connStrings = config.ConnectionStrings; if (connStrings != null && connStrings.SectionInformation.IsProtected && !connStrings.ElementInformation.IsLocked) { connStrings.SectionInformation.UnprotectSection(); } }
Bicicleta
Cuando hay una transformación de archivo y necesita cifrar secciones por separado de toda la configuración, solo es adecuada una versión autoescrita. Creamos una instancia de la clase RsaProtectedConfigurationProvider, tomamos un nodo de xml y lo ciframos por separado, luego reemplazamos el nodo en nuestro xml original con nuestro cifrado y guardamos el resultado.
public void Protect(string filePath, string sectionName = null) { XmlDocument xmlDocument = new XmlDocument { PreserveWhitespace = true }; xmlDocument.Load(filePath); if (xmlDocument.DocumentElement == null) { throw new InvalidXmlException($"Invalid Xml document"); } sectionName = !string.IsNullOrEmpty(sectionName) ? sectionName : xmlDocument.DocumentElement.Name; var xmlElement = xmlDocument.GetElementsByTagName(sectionName)[0] as XmlElement; var config = new NameValueCollection { { "keyContainerName", _settings.KeyContainerName }, { "useMachineContainer", _settings.UseMachineContainer ? "true" : "false" } }; var rsaProvider = new RsaProtectedConfigurationProvider(); rsaProvider.Initialize(_encryptionProviderSettings.ProviderName, config); var encryptedData = rsaProvider.Encrypt(xmlElement); encryptedData = xmlDocument.ImportNode(encryptedData, true); var createdXmlElement = xmlDocument.CreateElement(sectionName); var xmlAttribute = xmlDocument.CreateAttribute("configProtectionProvider"); xmlAttribute.Value = _encryptionProviderSettings.ProviderName; createdXmlElement.Attributes.Append(xmlAttribute); createdXmlElement.AppendChild(encryptedData); if (createdXmlElement.ParentNode == null || createdXmlElement.ParentNode.NodeType == XmlNodeType.Document || xmlDocument.DocumentElement == null) { XmlDocument docNew = new XmlDocument { InnerXml = createdXmlElement.OuterXml }; docNew.Save(filePath); } else { xmlDocument.DocumentElement.ReplaceChild(createdXmlElement, xmlElement); xmlDocument.Save(filePath); } }
Referencias
1.docs.microsoft.com/en-us/previous-versions/53tyfkaw2.support.microsoft.com/en-za/help/4466942/understanding-identities-in-iis