配置文件加密

背景知识


我的任务是设置CI。 决定使用配置文件的转换并以加密形式存储机密数据。 您可以使用密钥容器对它们进行加密和解密。

钥匙箱


每个Windows操作系统都有几组生成的密钥。 密钥在帐户或计算机上生成。 可以沿着以下路径查看计算机生成的密钥:C:\ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys。 这是我们接下来创建的密钥所在的位置。

密钥创建


我们从管理员启动cmd,然后使用aspnet_regiis切换到目录,我将其设置为C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319

执行命令

aspnet_regiis -pc "TestKey" -exp 

exp-已添加,以便将来可以导出密钥
TestKey-我们的密钥容器的名称

密钥导出


团队

 aspnet_regiis -px "TestKey" :\TestKey.xml -pri 

TestKey-名称密钥容器
C:\ TestKey.xml-文件将导出到的路径
pri-添加私钥以导出

导入密钥


团队

 aspnet_regiis -pi "TestKey" :\TestKey.xml 

TestKey-名称密钥容器
C:\ TestKey.xml-从中导出文件的路径

设定权


为了使您的应用程序或IIS使用密钥容器,您需要为其配置权限。

这是由团队完成的

 aspnet_regiis -pa "TestKey" "NT AUTHORITY\NETWORK SERVICE" 

TestKey-名称密钥容器
NT AUTHORITY \ NETWORK SERVICE-将为谁提供访问密钥的权限

默认情况下,IIS具有池的ApplicationPoolIdentity。

Microsoft文档(请参阅链接2)将ApplicationPoolIdentity描述为:

  • ApplicationPoolIdentity :创建新的应用程序池时,IIS将创建一个虚拟帐户,该帐户具有新应用程序池的名称,并在该帐户下运行应用程序池工作进程。 这也是特权最少的帐户。

因此,为了使IIS能够解密配置,必须在帐户的池中配置身份,或者您可以选择“网络服务”并为其授予权限。

在配置中添加一个部分


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

此外,密钥容器和RsaProtectedConfigurationProvider在文件中全局定义

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> = “System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration,版本= 4.0.0.0,文化=中性公钥= b03f5f7f11d50a3a”描述= “CryptProtectData和CryptUnProtectData的Windows API用于加密和解密” useMachineProtection = <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> 

加密方式


加密本身可以通过三种方式完成。

命令行加密


 aspnet_regiis.exe -pef connectionStrings :\Site -prov "CustomRsaProtectedConfigurationProvider" 

C:\ Site-带有配置文件的路径。

CustomRsaProtectedConfigurationProvider-在配置中指定的提供程序,称为密钥容器。

通过书面申请进行加密


 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(); } } 

单车


当进行文件转换时,您需要将部分与整个配置分开加密,那么仅适用于自写版本。 我们创建RsaProtectedConfigurationProvider类的实例,从xml中获取一个节点并单独对其进行加密,然后用经过加密的节点替换原始xml中的节点并保存结果。

 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); } } 

参考文献


1.docs.microsoft.com/zh-CN/previous-versions/53tyfkaw
2.support.microsoft.com/zh-CN/help/4466942/understanding-identities-in-iis

Source: https://habr.com/ru/post/zh-CN462379/


All Articles