Шифрование конфигурационных файлов

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Предыстория


Мне поступила задача по настройке CI. Было принято решение использовать трансформацию конфигурационных файлов и конфиденциальные данные хранить в зашифрованном виде.
Изучив документацию по шифрованию, вот что было сделано.

Key Container


В каждой ОС 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 — название нашего Key Container

Экспорт ключа


Команда

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

TestKey — название Key Container
С:\TestKey.xml — путь куда будет экспортирован файл
pri — добавить в экспорт приватный ключ

Импорт ключа


Команда

aspnet_regiis -pi "TestKey" С:\TestKey.xml

TestKey — название Key Container
С:\TestKey.xml — путь откуда будет экспортирован файл

Настройка прав


Чтобы ваше приложение или IIS могли работать с key container нужно настроить им права.

Делается это командой

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

TestKey — название Key Container
NT AUTHORITY\NETWORK SERVICE — кому будет выдан доступ до ключа

По умолчанию в IIS стоит ApplicationPoolIdentity для пула.

В документации Microsoft (см. ссылка 2) ApplicationPoolIdentity описан как:

  • ApplicationPoolIdentity: When a new application pool is created, IIS creates a virtual account that has the name of the new application pool and that runs the application pool worker process under this account. This is also a least-privileged account.

Поэтому чтобы IIS смог расшифровать конфиг, обязательно должна быть настроена Identity у пула на учетную запись или можно выбрать «NETWORK SERVICE» и для него дать права.

Добавление секции в config


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

Также key container и 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>

Шифрование


Само шифрование можно сделать тремя способами

Шифрование через командную строку


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

С:\Site — путь до файла с конфигом.

CustomRsaProtectedConfigurationProvider — наш провайдер указанный в конфиге с названием key container.

Шифрование через написанное приложение


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/en-us/previous-versions/53tyfkaw
2. support.microsoft.com/en-za/help/4466942/understanding-identities-in-iis
Источник: https://habr.com/ru/post/462379/


Интересные статьи

Интересные статьи

Я, исследуя устойчивость хранения данных в облачных системах, решил проверить себя, убедиться в том, что понимаю базовые вещи. Я начал с чтения спецификации NVMe для того чтобы разобратьс...
Один из ключевых сценариев работы в CRM это общение с клиентом в удобном для него канале. По почте, по телефону, по SMS или в мессенджере. Особенно выделяется WhatsApp — интеграцию с ...
Слышали ли вы о функциональном шифровании (ФШ)? Возможно, вы слышали о нём, и для себя поставили его в один ряд с гомоморфным шифрованием, что не совсем неверно, но и не до конца правильно. ...
Устраивать конкурсы в инстаграме сейчас модно. И удобно. Инстаграм предоставляет достаточно обширный API, который позволяет делать практически всё, что может сделать обычный пользователь ручками.
Привет, Хабр! Лето за окном пролетает для нас почти незаметно, потому что все эти месяцы мы посвятили работе над новым релизом 2019.2 нашей кросс-платформенной среды для разработки на C++ — CL...