Строки подключения и файлы конфигурации

Внедрение строк соединения в код приложения может привести к появлению уязвимых мест в системе безопасности и проблем с обслуживанием. Незашифрованные строки подключения, скомпилированные в исходный код приложения, можно просматривать с помощью средства Ildasm.exe (IL Disassembler). Кроме того, после изменения строки соединения необходимо перекомпилировать приложение. По этим причинам рекомендуется хранить строки соединения в файле конфигурации приложения.

Работа с файлами конфигурации приложения

Файлы конфигурации приложения содержат настройки, относящиеся к отдельному приложению. Например, приложение ASP.NET может иметь один или несколько файлов web.config, а приложение Windows — дополнительный файл app.config. В файлах конфигурации присутствуют общие элементы, хотя имя и расположение любого файла конфигурации в значительной степени зависят от того, где размещается приложение.

Раздел connectionStrings

Строки подключения могут храниться в виде пар "ключ/значение" в разделе connectionStrings элемента configuration файла конфигурации приложения. Дочерние элементы включают add, clear и remove.

Следующий фрагмент файла конфигурации демонстрирует схему и синтаксис хранения строки соединения. Атрибут name является именем, которое задано для уникальной идентификации строки подключения, чтобы ее можно было получить во время выполнения. Атрибут providerName является неизменяемым именем поставщика данных .NET Framework, которое регистрируется в файле machine.config.

<?xml version='1.0' encoding='utf-8'?>  
  <configuration>  
    <connectionStrings>  
      <clear />  
      <add name="Name"
       providerName="System.Data.ProviderName"
       connectionString="Valid Connection String;" />  
    </connectionStrings>  
  </configuration>  

Примечание.

Можно сохранить часть строки соединения в файле конфигурации и для ее дополнения во время выполнения использовать класс DbConnectionStringBuilder. Это удобно в сценариях, в которых заранее неизвестны элементы строки соединения или желательно не сохранять конфиденциальные данные в файле конфигурации. Дополнительные сведения см. в статье Connection String Builders (Построители строк подключения).

Использование внешних файлов конфигурации

Внешние файлы конфигурации представляют собой отдельные файлы, каждый из которых содержит фрагмент файла конфигурации, состоящий из одного раздела. В таком случае основной файл конфигурации ссылается на внешний файл конфигурации. Хранение раздела connectionStrings в физически отдельном файле становится удобным в ситуациях, когда может потребоваться внесение изменений в строки подключения после развертывания приложения. Например, в ASP.NET по умолчанию после изменения файлов конфигурации осуществляется перезапуск домена приложения, что приводит к потере сведений о состоянии. Но изменение внешнего файла конфигурации не вызывает перезапуск приложения. Возможность применения внешних файлов конфигурации не ограничивается ASP.NET; их можно также использовать в приложениях Windows. Кроме того, для ограничения доступа к внешним файлам конфигурации могут использоваться средства обеспечения безопасности доступа к файлам и разрешения. Работа с внешними файлами конфигурации во время выполнения осуществляется в прозрачном режиме и не требует разработки специального кода.

Для хранения строк подключения во внешнем файле конфигурации создайте отдельный файл, содержащий единственный раздел connectionStrings. Не следует включать какие-либо дополнительные элементы, разделы или атрибуты. В данном примере показан синтаксис внешнего файла конфигурации.

<connectionStrings>  
  <add name="Name"
   providerName="System.Data.ProviderName"
   connectionString="Valid Connection String;" />  
</connectionStrings>  

В основном файле конфигурации приложения для указания полного имени и расположения внешнего файла используется атрибут configSource. В следующем примере применяется ссылка на внешний файл конфигурации с именем connections.config.

<?xml version='1.0' encoding='utf-8'?>  
<configuration>  
    <connectionStrings configSource="connections.config"/>  
</configuration>  

Получение строк соединения во время выполнения

В .NET Framework 2.0 в пространстве имен System.Configuration появились новые классы, упрощающие извлечение строк подключения из файлов конфигурации во время выполнения. Предусмотрена возможность получить строку соединения программным путем по ее имени или по имени поставщика.

Примечание.

Файл machine.config также содержит раздел connectionStrings, включающий строку подключения, используемую Visual Studio. При получении строка подключения по имени поставщика из файла app.config в приложении Windows сначала загружаются строка подключения в machine.config, а затем записи из app.config. Добавление ясно сразу после того, как элемент connectionStrings удаляет все унаследованные ссылки из структуры данных в памяти, чтобы считаться только строка подключения, определенные в локальном файле app.config.

Работа с классами конфигурации

Начиная с платформа .NET Framework 2.0, ConfigurationManager используется при работе с файлами конфигурации на локальном компьютере, заменив устаревшиеConfigurationSettings. WebConfigurationManager служит для работы с файлами конфигурации ASP.NET. Он создан для работы с файлами конфигурации веб-сервера и предоставляет программный доступ к разделам файла конфигураций, например system.web.

Примечание.

Вызывающему объекту для доступа к файлам конфигурации во время выполнения должны быть предоставлены разрешения. Требуемые разрешения зависят от типа приложения, файла конфигурации и расположения. Дополнительные сведения см. в разделах Использование классов конфигурации и WebConfigurationManager для приложений ASP.NET и ConfigurationManager для приложений Windows.

Для получения строк соединения из файлов конфигурации приложения используется ConnectionStringSettingsCollection. Этот объект содержит коллекцию объектов ConnectionStringSettings, каждый из которых представляет одну запись в разделе connectionStrings. Его свойства сопоставляются с атрибутами строк соединения, что позволяет получить строку соединения, указав имя строки или имя поставщика.

Свойство Description
Name Имя строки соединения. Сопоставляется с атрибутом name.
ProviderName Полное имя поставщика. Сопоставляется с атрибутом providerName.
ConnectionString Строка подключения. Сопоставляется с атрибутом connectionString.

Пример. Список всех строк соединения

В этом примере выполняется итерация ConnectionStringSettingsCollection и отображаются свойства ConnectionStringSettings.Name, ConnectionStringSettings.ProviderName и ConnectionStringSettings.ConnectionString в окне консоли.

Примечание.

Файл System.Configuration.dll не включается в проекты всех типов, поэтому для использования классов конфигурации может потребоваться сформировать на него ссылку. Имя и расположение файла конфигурации определенного приложения зависит от типа приложения и процесса размещения.

using System.Configuration;

static class Program
{
    static void Main()
    {
        GetConnectionStrings();
        Console.ReadLine();
    }

    static void GetConnectionStrings()
    {
        ConnectionStringSettingsCollection settings =
            ConfigurationManager.ConnectionStrings;

        foreach (ConnectionStringSettings cs in settings)
        {
            Console.WriteLine(cs.Name);
            Console.WriteLine(cs.ProviderName);
            Console.WriteLine(cs.ConnectionString);
        }
    }
}
Imports System.Configuration

Class Program
    Shared Sub Main()
        GetConnectionStrings()
        Console.ReadLine()
    End Sub

    Private Shared Sub GetConnectionStrings()

        Dim settings As ConnectionStringSettingsCollection = _
            ConfigurationManager.ConnectionStrings

        If Not settings Is Nothing Then
            For Each cs As ConnectionStringSettings In settings
                Console.WriteLine(cs.Name)
                Console.WriteLine(cs.ProviderName)
                Console.WriteLine(cs.ConnectionString)
            Next
        End If
    End Sub
End Class

Пример. Извлечение строки соединения по имени

Данный пример демонстрирует способ получения строки соединения из файла конфигурации путем указания ее имени. Код создает объект ConnectionStringSettings, сопоставляя указанный входной параметр с именем ConnectionStrings. Если совпадающее имя не найдено, функция возвращает значение null (Nothing в Visual Basic).

// Retrieves a connection string by name.
// Returns null if the name is not found.
static string? GetConnectionStringByName(string name)
{
    // Look for the name in the connectionStrings section.
    ConnectionStringSettings? settings =
        ConfigurationManager.ConnectionStrings[name];

    // If found, return the connection string (otherwise return null)
    return settings?.ConnectionString;
}
' Retrieves a connection string by name.
' Returns Nothing if the name is not found.
Private Shared Function GetConnectionStringByName( _
    ByVal name As String) As String

    ' Assume failure
    Dim returnValue As String = Nothing

    ' Look for the name in the connectionStrings section.
    Dim settings As ConnectionStringSettings = _
       ConfigurationManager.ConnectionStrings(name)

    ' If found, return the connection string.
    If Not settings Is Nothing Then
        returnValue = settings.ConnectionString
    End If

    Return returnValue
End Function

Пример. Извлечение строки соединения по имени поставщика

В этом примере демонстрируется способ получения строки подключения путем указания неизменяемого имени поставщика в формате System.Data.ProviderName. В коде выполняется итерация по ConnectionStringSettingsCollection и происходит возврат строки соединения для первого найденного ProviderName. Если имя поставщика не найдено, функция возвращает значение null (Nothing в Visual Basic).

// Retrieve a connection string by specifying the providerName.
// Assumes one connection string per provider in the config file.
static string? GetConnectionStringByProvider(string providerName)
{
    // Get the collection of connection strings.
    ConnectionStringSettingsCollection? settings =
        ConfigurationManager.ConnectionStrings;

    // Walk through the collection and return the first
    // connection string matching the providerName.
    if (settings != null)
    {
        foreach (ConnectionStringSettings cs in settings)
        {
            if (cs.ProviderName == providerName)
            {
                return cs.ConnectionString;
            }
        }
    }
    return null;
}
' Retrieve a connection string by specifying the providerName.
' Assumes one connection string per provider in the config file.
Private Shared Function GetConnectionStringByProvider( _
    ByVal providerName As String) As String

    'Return Nothing on failure.
    Dim returnValue As String = Nothing

    ' Get the collection of connection strings.
    Dim settings As ConnectionStringSettingsCollection = _
        ConfigurationManager.ConnectionStrings

    ' Walk through the collection and return the first 
    ' connection string matching the providerName.
    If Not settings Is Nothing Then
        For Each cs As ConnectionStringSettings In settings
            If cs.ProviderName = providerName Then
                returnValue = cs.ConnectionString
                Exit For
            End If
        Next
    End If

    Return returnValue
End Function

Шифрование разделов файлов конфигурации с использованием защищенной конфигурации

В ASP.NET 2.0 появилась новая возможность, защищенная конфигурация, с помощью которой можно шифровать в файле конфигурации конфиденциальную информацию. Защищенная конфигурация разрабатывалась в первую очередь для ASP.NET, но ее можно также использовать для шифрования разделов файлов конфигурации в приложениях Windows. Подробное описание возможностей защищенной конфигурации см. в разделе Шифрование сведений о конфигурации с помощью функции защищенной конфигурации.

В приведенном ниже фрагменте файла конфигурации показан раздел connectionStrings после шифрования. В разделе configProtectionProvider задается поставщик защищенной конфигурации, который используется для шифрования и дешифрования строк подключения. Раздел EncryptedData содержит зашифрованный текст.

<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">  
  <EncryptedData>  
    <CipherData>  
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAH2... </CipherValue>  
    </CipherData>  
  </EncryptedData>  
</connectionStrings>  

Когда зашифрованная строка подключения извлекается во время выполнения, платформа .NET Framework с помощью указанного поставщика дешифрует значение CipherValue и передает его приложению. Нет необходимости создавать дополнительный код для управления процессом дешифрования.

Поставщики защищенной конфигурации

Поставщики защищенной конфигурации регистрируются в разделе configProtectedData файла machine.config на локальном компьютере, как показано в приведенном ниже фрагменте, в котором демонстрируются два поставщика защищенной конфигурации, поставляемые с платформой .NET Framework. Показанные значения были усечены для удобства чтения.

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">  
  <providers>  
    <add name="RsaProtectedConfigurationProvider"
      type="System.Configuration.RsaProtectedConfigurationProvider" />  
    <add name="DataProtectionConfigurationProvider"
      type="System.Configuration.DpapiProtectedConfigurationProvider" />  
  </providers>  
</configProtectedData>  

Можно назначить дополнительные поставщики защищенной конфигурации, добавляя их в файл machine.config. Кроме того, можно создать собственный поставщик защищенной конфигурации путем наследования от абстрактного базового класса ProtectedConfigurationProvider. В приведенной ниже таблице дано описание двух файлов конфигурации, входящих в платформу .NET Framework.

Provider Description
RsaProtectedConfigurationProvider Использует алгоритм RSA для шифрования и расшифровки данных. Алгоритм RSA можно использовать для шифрования с открытым ключом и цифровых сигнатур. Он также известен как алгоритм с «открытым ключом» или алгоритм асимметричного шифрования, поскольку в нем используется два разных ключа. Для шифрования разделов в файле Web.config и управления ключами шифрования можно использовать средство регистрации служб IIS ASP.NET (Aspnet_regiis.exe). ASP.NET расшифровывает файл конфигурации при обработке файла. Удостоверение приложения ASP.NET должно иметь права на чтение ключа шифрования, который используется для шифрования и расшифровки зашифрованных разделов.
DpapiProtectedConfigurationProvider Использует API-интерфейс защиты данных (DPAPI) для шифрования разделов конфигурации. Он использует встроенные службы шифрования Windows и может быть настроен для защиты отдельных компьютеров или отдельных учетных записей пользователей. Защиту отдельных компьютеров удобно использовать для нескольких приложений на одном сервере, которым требуется совместное использование данных. Защиту учетных записей можно использовать со службами, выполняемыми с определенным удостоверением пользователя, например с общей средой размещения. Каждое приложение выполняется с отдельным удостоверением, которое ограничивает доступ к ресурсам, например к файлам и базам данных.

Оба поставщика обеспечивают надежное шифрование данных. Однако, если планируется использовать один файл конфигурации на нескольких серверах, как в веб-ферме, то только RsaProtectedConfigurationProvider позволяет экспортировать ключи шифрования, применяемые для шифрования данных, и импортировать их в другой сервер. Дополнительные сведения см. в разделе Импорт и экспорт защищенных контейнеров ключей RSA для конфигурации.

Использование классов конфигурации

Пространство имен System.Configuration предоставляет классы для программной обработки параметров конфигурации. Класс ConfigurationManager обеспечивает доступ к компьютеру, приложению и пользовательским файлам конфигурации. При создании приложения ASP.NET можно использовать класс WebConfigurationManager, который предоставляет те же функциональные возможности и одновременно позволяет обращаться к уникальным настройкам приложений ASP.NET, в частности, в файле <system.web>.

Примечание.

Пространство имен System.Security.Cryptography содержит классы, которые предоставляют дополнительные возможности шифрования и расшифровки данных. Эти классы можно использовать в том случае, если требуются криптографические службы, недоступные с использованием защищенной конфигурации. Некоторые из этих классов являются оболочками для Microsoft CryptoAPI, а другие представляют собой реализации полностью на управляемом коде. Дополнительные сведения см. в разделе Службы криптографии.

Пример App.config

Этот пример демонстрирует переключение шифрования раздела connectionStrings в файле app.config для приложения Windows. В этом примере процедура принимает имя приложения в качестве аргумента, например, «MyApplication.exe». Затем файл app.config зашифровывается и копируется в папку, которая содержит исполняемый файл с именем MyApplication.exe.config.

Примечание.

Строку соединения можно расшифровать только на компьютере, где она была зашифрована.

В коде используется метод OpenExeConfiguration, чтобы открыть файл app.config для изменения, а метод GetSection возвращает раздел connectionStrings. Затем код проверяет свойство IsProtected, вызывая метод ProtectSection для шифрования раздела, если он не зашифрован. Метод UnprotectSection вызывается для расшифровки раздела. Метод Save завершает операцию и сохраняет изменения.

Примечание.

Для запуска кода необходимо задать ссылку на System.Configuration.dll в проекте.

static void ToggleConfigEncryption(string exeFile)
{
    // Get the application path needed to obtain
    // the application configuration file.

    // Takes the executable file name without the
    // .config extension.
    var exePath = exeFile.Replace(".config", "");

    try
    {
        // Open the configuration file and retrieve
        // the connectionStrings section.
        Configuration config = ConfigurationManager.
            OpenExeConfiguration(exePath);

        var section =
            config.GetSection("connectionStrings")
            as ConnectionStringsSection;

        if (section != null)
        {
            if (section.SectionInformation.IsProtected)
            {
                // Remove encryption.
                section.SectionInformation.UnprotectSection();
            }
            else
            {
                // Encrypt the section.
                section.SectionInformation.ProtectSection(
                    "DataProtectionConfigurationProvider");
            }
        }
        // Save the current configuration.
        config.Save();

        Console.WriteLine("Protected={0}",
            section?.SectionInformation.IsProtected);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Shared Sub ToggleConfigEncryption(ByVal exeConfigName As String)
    ' Takes the executable file name without the
    ' .config extension.
    Try
        ' Open the configuration file and retrieve 
        ' the connectionStrings section.
        Dim config As Configuration = ConfigurationManager. _
            OpenExeConfiguration(exeConfigName)

        Dim section As ConnectionStringsSection = DirectCast( _
            config.GetSection("connectionStrings"), _
            ConnectionStringsSection)

        If section.SectionInformation.IsProtected Then
            ' Remove encryption.
            section.SectionInformation.UnprotectSection()
        Else
            ' Encrypt the section.
            section.SectionInformation.ProtectSection( _
              "DataProtectionConfigurationProvider")
        End If

        ' Save the current configuration.
        config.Save()

        Console.WriteLine("Protected={0}", _
        section.SectionInformation.IsProtected)

    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try
End Sub

Пример Web.config

В этом примере используется метод OpenWebConfiguration класса WebConfigurationManager. Обратите внимание, что в этом случае можно задать относительный путь к файлу Web.config с использованием символа "тильда". В коде должна быть ссылка на класс System.Web.Configuration.

static void ToggleWebEncrypt()
{
    // Open the Web.config file.
    Configuration config = WebConfigurationManager.
        OpenWebConfiguration("~");

    // Get the connectionStrings section.
    var section =
        config.GetSection("connectionStrings")
        as ConnectionStringsSection;

    // Toggle encryption.
    if (section.SectionInformation.IsProtected)
    {
        section.SectionInformation.UnprotectSection();
    }
    else
    {
        section.SectionInformation.ProtectSection(
            "DataProtectionConfigurationProvider");
    }

    // Save changes to the Web.config file.
    config.Save();
}
Shared Sub ToggleWebEncrypt()
    ' Open the Web.config file.
    Dim config As Configuration = WebConfigurationManager. _
      OpenWebConfiguration("~")

    ' Get the connectionStrings section.
    Dim section As ConnectionStringsSection = DirectCast( _
        config.GetSection("connectionStrings"), _
        ConnectionStringsSection)

    ' Toggle encryption.
    If section.SectionInformation.IsProtected Then
        section.SectionInformation.UnprotectSection()
    Else
        section.SectionInformation.ProtectSection( _
          "DataProtectionConfigurationProvider")
    End If

    ' Save changes to the Web.config file.
    config.Save()
End Sub

Дополнительные сведения о защите приложений ASP.NET см. в статье Защита веб-сайтов ASP.NET.

См. также