Using Always Encrypted with the .NET Framework Data Provider for SQL Server (Использование Always Encrypted с поставщиком данных .NET Framework для SQL Server)

Применяется к:SQL ServerAzure SQL DatabaseAzure, управляемому экземпляру SQL Azure

В этой статье содержатся сведения о разработке приложений .NET Framework с помощью Always Encrypted или Always Encrypted с безопасными анклавами и поставщиком данных .NET Framework для SQL Server (System.Data.SqlClient).

Заметка

Использование поставщика данных .NET Framework для SQL Server (System.Data.SqlClient) не рекомендуется для новой разработки. Дополнительные сведения см. в разделе System.Data.SqlClient.

Функция Always Encrypted позволяет шифровать конфиденциальные данные в клиентских приложениях, не раскрывая данные или ключи шифрования для SQL Server или Базы данных SQL Azure. Драйвер с поддержкой постоянного шифрования, такой как поставщик данных .NET Framework для SQL Server, реализует это за счет прозрачного шифрования и расшифровки конфиденциальных данных в клиентском приложении SQL Server. Драйвер автоматически определяет, какие параметры запроса соответствуют важным столбцам базы данных (защищенным с помощью Always Encrypted), и шифрует значения этих параметров перед передачей данных в SQL Server или Базу данных SQL Azure. Аналогичным образом драйвер прозрачно расшифровывает данные, полученные из зашифрованных столбцов базы в результатах запроса. Дополнительные сведения см. в разделе Разработка приложений с помощью Always Encrypted и Разработка приложений с помощью Always Encrypted с безопасными анклавами.

Заметка

Поставщик данных .NET Framework для SQL Server (System.Data.SqlClient) не поддерживает использование анклавов VBS без аттестации.

Предварительные условия

  • Настройте функцию постоянного шифрования в базе данных. В процесс настройки входят действия по подготовке ключей постоянного шифрования и настройке шифрования для выбранных столбцов базы данных. Если у вас еще нет базы данных с настроенным Always Encrypted, следуйте инструкциям в руководстве по началу работы с Always Encrypted.
  • Если вы используете Always Encrypted с безопасными анклавами, см. статью Разработка приложений с помощью Always Encrypted с безопасными анклавами со сведениями о дополнительных предварительных требованиях.
  • Убедитесь, что на компьютере, предназначенном для разработки, установлена платформа .NET Framework 4.6.1 или более поздней версии. Дополнительные сведения см. в разделе .NET Framework 4.6. Также необходимо убедиться, что в среде разработки в качестве целевой версии платформы установлена платформа .NET Framework 4.6 или более поздней версии. Если вы используете Visual Studio, обратитесь к разделу "Практическое руководство. Целевая версия .NET Framework".

Заметка

Уровень поддержки постоянного шифрования зависит от конкретной версии платформы .NET Framework. Ссылки на API Always Encrypted перечислены в следующих разделах.

Включение постоянного шифрования для запросов приложений

Самым простым способом включения шифрования параметров и расшифровки результатов запросов к зашифрованным столбцам является установка для ключевого слова строки подключения "Параметр шифрования столбца" значения Включено.

Ниже приведен пример строки подключения, включающий постоянное шифрование.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
SqlConnection connection = new SqlConnection(connectionString);

Далее приведен эквивалент примера с использованием свойства SqlConnectionStringBuilder.ColumnEncryptionSetting.

SqlConnectionStringBuilder strbldr = new SqlConnectionStringBuilder();
strbldr.DataSource = "server63";
strbldr.InitialCatalog = "Clinic";
strbldr.IntegratedSecurity = true;
strbldr.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
SqlConnection connection = new SqlConnection(strbldr.ConnectionString);

Постоянное шифрование также можно включить для отдельных запросов. См. раздел Управление влиянием постоянного шифрования на производительность ниже. Включения функции Always Encrypted недостаточно для успешного шифрования или расшифровки. Необходимо также проверить выполнение следующих условий:

  • Приложение имеет разрешения VIEW ANY COLUMN MASTER KEY DEFINITION и VIEW ANY COLUMN ENCRYPTION KEY DEFINITION для базы данных, необходимые для доступа к метаданным о ключах постоянного шифрования в базе данных. Для дополнительных сведений см. страницу о разрешениях в статье "Always Encrypted (ядро СУБД)".
  • Приложение может получить доступ к главному ключу столбца, который защищает ключи шифрования столбцов, шифрующие запрашиваемые столбцы базы данных.

Включение Always Encrypted с безопасными анклавами

Начиная с версии .NET Framework 4.7.2 драйвер поддерживает Always Encrypted с безопасными анклавами.

Общие сведения о роли клиентского драйвера в вычислениях анклава и аттестации анклава см. в статье Разработка приложений с помощью Always Encrypted с безопасными анклавами.

Настройка приложения:

  1. Включите Always Encrypted для запросов приложения, как описано в предыдущем разделе.

  2. Интегрируйте пакет NuGet Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders в приложение. NuGet — это библиотека поставщиков анклавов, которая реализует логику на стороне клиента для протокола аттестации, а также для установки безопасного канала с безопасным анклавом.

  3. Измените конфигурацию приложения (например, в файле web.config или app.config), чтобы определить сопоставление типа анклава, настроенного для базы данных, и поставщика анклава.

    1. Если вы используете службу защиты SQL Server и узла (HGS), необходимо сопоставить тип анклава VBS с классом Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders.HostGuardianServiceEnclaveProvider из пакета NuGet.
    2. Если вы используете базу данных SQL Azure и аттестацию Microsoft Azure, необходимо сопоставить тип анклавов SGX с классом Microsoft.SqlServer.Management.AlwaysEncrypted.EnclaveProviders.AzureAttestationEnclaveProvider из пакета NuGet.

    Подробные инструкции по изменению конфигурации приложения см. в руководстве по разработке приложения .NET Framework с помощью Always Encrypted с безопасными анклавами.

  4. В строке подключения к базе данных задайте для ключевого слова Enclave Attestation URL URL-адрес аттестации (конечная точка службы аттестации). Необходимо получить URL-адрес аттестации для имеющейся среды у администратора службы аттестации.

    1. Если вы используете службу защиты SQL Server и узла (HGS), ознакомьтесь с разделом "Определение и предоставление общего доступа к URL-адресу аттестации HGS".
    2. Если вы используете базу данных SQL Azure и аттестацию Microsoft Azure, ознакомьтесь с URL-адресом аттестации для политики аттестации.

Пошаговое руководство по разработке приложения .NET Framework с помощью Always Encrypted с безопасными анклавами

Получение и изменение данных в зашифрованных столбцах

После включения постоянного шифрования для запросов приложений можно использовать стандартные API-интерфейсы для ADO.NET (см. раздел Получение и изменение данных в ADO.NET) или API-интерфейсы поставщика данных .NET Framework для SQL Server , определенные в пространстве имен System.Data.SqlClient, чтобы получать или изменять данные в зашифрованных столбцах базы данных. Если приложение имеет необходимые разрешения для базы данных и может обращаться к главному ключу столбца, поставщик данных .NET Framework для SQL Server будет шифровать все параметры запроса, предназначенные для зашифрованных столбцов, и расшифровывать данные, извлекаемые из зашифрованных столбцов с возвращаемыми значениями типов .NET в виде открытого текста, которые соответствуют типам данным SQL Server, заданным для столбцов в схеме базы данных. Если функция Always Encrypted не включена, выполнение запросов с параметрами, предназначенными для зашифрованных столбцов, завершится ошибкой. Запросы по-прежнему могут получать данные из зашифрованных столбцов, пока для них не будут указаны параметры, предназначенные для зашифрованных столбцов. Однако поставщик данных .NET Framework для SQL Server не будет пытаться расшифровать все значения, полученные из зашифрованных столбцов, и приложение будет получать двоичные зашифрованные данные (в виде массивов байтов).

В приведенной ниже таблице описывается поведение запросов в зависимости от того, включено постоянное шифрование или нет.

Характеристика запроса Постоянное шифрование включено, и приложение может получать доступ к ключам и метаданным ключей Функция Always Encrypted включена, и приложение не может получать доступ к ключам и метаданным ключей Постоянное шифрование отключено
Запросы с параметрами, предназначенными для зашифрованных столбцов. Значения параметров прозрачно шифруются. Ошибка Ошибка
Запросы, получающие данные из зашифрованных столбцов, без параметров, предназначенных для зашифрованных столбцов. Результаты из зашифрованных столбцов прозрачно расшифровываются. Приложение получает значения типов данных .NET в виде открытого текста, которые соответствуют типам SQL Server, настроенным для зашифрованных столбцов. Ошибка Результаты из зашифрованных столбцов не расшифровываются. Приложение получает зашифрованные значения в виде массивов байтов (byte[]).

В следующих примерах показано получение и изменение данных в зашифрованных столбцах. В примерах предполагается использование целевой таблицы с приведенной ниже схемой. Столбцы SSN и BirthDate зашифрованы.

CREATE TABLE [dbo].[Patients]([PatientId] [int] IDENTITY(1,1), 
 [SSN] [char](11) COLLATE Latin1_General_BIN2 
 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, 
 ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', 
 COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL,
 [FirstName] [nvarchar](50) NULL,
 [LastName] [nvarchar](50) NULL, 
 [BirthDate] [date] 
 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, 
 ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', 
 COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL
 PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY])
 GO

Пример вставки данных

В этом примере показана вставка строки в таблицу Patients. Обратите внимание на следующее.

  • В примере кода нет ничего, связанного с шифрованием. Поставщик данных .NET Framework для SQL Server автоматически обнаруживает и шифрует параметры paramSSN и paramBirthdate , предназначенные для зашифрованных столбцов. В этом случае шифрование является прозрачным для приложения.
  • Значения, вставляемые в столбцы базы данных, включая зашифрованные столбцы, передаются как объекты SqlParameter . Несмотря на то, что при отправке значений в незашифрованные столбцы использовать параметр SqlParameter необязательно (но настоятельно рекомендуется, так как он помогает предотвратить внедрение кода SQL), он требуется для значений, предназначенных для зашифрованных столбцов. Если значения, вставляемые в столбцы SSN или BirthDate, были переданы в виде литералов, внедренных в инструкцию запроса, запрос завершится ошибкой, так как поставщик данных .NET Framework для SQL Server не сможет определить значения в целевых зашифрованных столбцах, поэтому он не зашифрует значения. В результате сервер отклонит их как несовместимые с зашифрованными столбцами.
  • Для типа данных параметра, предназначенного для столбца SSN, задана строка ANSI (отличная от Юникода), которая сопоставляется с типом данных char и varchar SQL Server. Если для типа параметра была задана строка в Юникоде (String), которая сопоставляется с типом данных char и varchar, выполнение запроса завершится ошибкой, так как постоянное шифрование не поддерживает преобразования из зашифрованных значений nchar и nvarchar в зашифрованные значения char и varchar. Сведения о сопоставлении типов данных см. в разделе Сопоставления типов данных SQL Server .
  • В качестве типа данных параметра, вставляемого в столбец BirthDate, явным образом задан целевой тип данных SQL Server. Для этого использовалось свойство SqlParameter.SqlDbType Property, а не неявное сопоставление типов .NET с типами данных SQL Server, применяемыми при работе со свойством SqlParameter.DbType Property. По умолчанию структура DateTime сопоставляется с типом данных datetime SQL Server. Так как тип данных столбца BirthDate имеет дату и Always Encrypted не поддерживает преобразование зашифрованных значений даты и времени в зашифрованные значения даты, используя сопоставление по умолчанию, приведет к ошибке.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
using (SqlConnection connection = new SqlConnection(strbldr.ConnectionString))
{
   using (SqlCommand cmd = connection.CreateCommand())
   {
      cmd.CommandText = @"INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (@SSN, @FirstName, @LastName, @BirthDate);";

      SqlParameter paramSSN = cmd.CreateParameter();
      paramSSN.ParameterName = @"@SSN";
      paramSSN.DbType = DbType.AnsiStringFixedLength;
      paramSSN.Direction = ParameterDirection.Input;
      paramSSN.Value = "795-73-9838";
      paramSSN.Size = 11;
      cmd.Parameters.Add(paramSSN);

      SqlParameter paramFirstName = cmd.CreateParameter();
      paramFirstName.ParameterName = @"@FirstName";
      paramFirstName.DbType = DbType.String;
      paramFirstName.Direction = ParameterDirection.Input;
      paramFirstName.Value = "Catherine";
      paramFirstName.Size = 50;
      cmd.Parameters.Add(paramFirstName);

      SqlParameter paramLastName = cmd.CreateParameter();
      paramLastName.ParameterName = @"@LastName";
      paramLastName.DbType = DbType.String;
      paramLastName.Direction = ParameterDirection.Input;
      paramLastName.Value = "Abel";
      paramLastName.Size = 50;
      cmd.Parameters.Add(paramLastName);

      SqlParameter paramBirthdate = cmd.CreateParameter();
      paramBirthdate.ParameterName = @"@BirthDate";
      paramBirthdate.SqlDbType = SqlDbType.Date;
      paramBirthdate.Direction = ParameterDirection.Input;
      paramBirthdate.Value = new DateTime(1996, 09, 10);
      cmd.Parameters.Add(paramBirthdate);

      cmd.ExecuteNonQuery();
   } 
}

Пример получения данных обычного текста

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

  • Значение, используемое в предложении WHERE для фильтрации по столбцу SSN, необходимо передать с помощью SqlParameter, чтобы поставщик данных .NET Framework для SQL Server мог его прозрачно зашифровать перед отправкой в базу данных.
  • Все значения, выводимые программой, будут представлены в виде обычного текста, так как поставщик данных .NET Framework для SQL Server прозрачно расшифровывает данные, полученные из столбцов SSN и BirthDate.

Заметка

Запросы могут выполнять сравнение на равенство для столбцов, если они шифруются с помощью детерминированного шифрования. Дополнительные сведения см. в разделе Выбор детерминированного или случайного шифрования.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column Encryption Setting=enabled";
    
using (SqlConnection connection = new SqlConnection(strbldr.ConnectionString))
 {
    using (SqlCommand cmd = connection.CreateCommand())
 {

 cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN=@SSN";
 SqlParameter paramSSN = cmd.CreateParameter();
 paramSSN.ParameterName = @"@SSN";
 paramSSN.DbType = DbType.AnsiStringFixedLength;
 paramSSN.Direction = ParameterDirection.Input;
 paramSSN.Value = "795-73-9838";
 paramSSN.Size = 11;
 cmd.Parameters.Add(paramSSN);
 using (SqlDataReader reader = cmd.ExecuteReader())
 {
   if (reader.HasRows)
 {
 while (reader.Read())
 {
    Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2], ((DateTime)reader[3]).ToShortDateString());
 }

Пример получения зашифрованных данных

Если функция Always Encrypted не включена, запрос может получать данные из зашифрованных столбцов, пока для него не будут указаны параметры, предназначенные для зашифрованных столбцов.

В следующем примере показано извлечение двоичных зашифрованных данных из зашифрованных столбцов. Обратите внимание на следующее.

  • Так как Always Encrypted не включается в строке подключения, запрос вернет зашифрованные значения SSN и BirthDate в виде байтовых массивов (программа преобразует эти значения в строки).
  • Запрос, получающий данные из зашифрованных столбцов с отключенным постоянным шифрованием, может иметь параметры при условии, что ни один из параметров не предназначен для зашифрованного столбца. Приведенный выше запрос выполняет фильтрацию по LastName, который не зашифрован в базе данных. Запрос, отфильтрованный по SSN или BirthDate, завершится ошибкой.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
                
using (SqlConnection connection = new SqlConnection(connectionString))
{
   connection.Open();
   using (SqlCommand cmd = connection.CreateCommand())
   {
      cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName]=@LastName";
      SqlParameter paramLastName = cmd.CreateParameter();
      paramLastName.ParameterName = @"@LastName";
      paramLastName.DbType = DbType.String;
      paramLastName.Direction = ParameterDirection.Input;
      paramLastName.Value = "Abel";
      paramLastName.Size = 50;
      cmd.Parameters.Add(paramLastName);
      using (SqlDataReader reader = cmd.ExecuteReader())
      {
         if (reader.HasRows)
         {
            while (reader.Read())
         {
         Console.WriteLine(@"{0}, {1}, {2}, {3}", BitConverter.ToString((byte[])reader[0]), reader[1], reader[2], BitConverter.ToString((byte[])reader[3]));
      }
   }
}

Как избежать распространенных проблем при запросе зашифрованных столбцов

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

Ошибки преобразования неподдерживаемых типов данных

Постоянное шифрование поддерживает несколько преобразований для зашифрованных типов данных. Подробный список поддерживаемых преобразований типов см. в статье Always Encrypted. Чтобы избежать ошибок при преобразовании типов данных, сделайте следующее:

  • Задайте типы параметров, предназначенных для зашифрованных столбцов, так, чтобы тип данных SQL Server параметра точно совпадал с типом целевого столбца или чтобы поддерживалось преобразование типа данных SQL Server параметра в целевой тип столбца. С помощью свойства SqlParameter.SqlDbType можно принудительно задать нужное сопоставление типов данных .NET с конкретными типами данных SQL Server.
  • Убедитесь, что точность и масштаб параметров, предназначенных для столбцов типов данных SQL Server decimal и numeric, соответствуют точности и масштабу, настроенным для целевого столбца.
  • Убедитесь, что точность параметров, предназначенных для столбцов типов данных SQL Server datetime2, datetimeoffset или time, не превышает точность для целевого столбца (в запросах, которые изменяют значения целевого столбца).

Ошибки, возникающие из-за передачи значений в виде открытого текста, а не в зашифрованном виде

Любое значение, предназначенное для зашифрованного столбца, должно быть зашифровано внутри приложения. Попытка вставки, изменения или фильтрации по значению в виде открытого текста в зашифрованном столбце приведет к возникновению ошибки, подобной следующей:

System.Data.SqlClient.SqlException (0x80131904): Operand type clash: varchar is incompatible with varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'Clinic') collation_name = 'SQL_Latin1_General_CP1_CI_AS'

Чтобы избежать таких ошибок, убедитесь, что:

  • функция Always Encrypted включена для запросов приложений, предназначенных для зашифрованных столбцов (для строки подключения или в отдельном объекте SqlCommand для конкретного запроса);
  • для отправки данных, предназначенных для зашифрованных столбцов, используется параметр SqlParameter. В примере ниже показан запрос, который вместо передачи литерала внутри объекта SqlParameter неправильно фильтрует по литералу или константе в зашифрованном столбце (SSN).
using (SqlCommand cmd = connection.CreateCommand())
{
   cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-73-9838'";
cmd.ExecuteNonQuery();
}

Работа с хранилищами главных ключей столбцов

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

Чтобы получить значение в виде открытого текста для ключа шифрования столбца, поставщик данных .NET Framework для SQL Server сначала получает метаданные о ключе шифрования столбца и соответствующем ему главном ключе столбца, а затем использует сведения в метаданных для доступа в хранилище ключей, содержащее главный ключ столбца, и для расшифровки ключа шифрования зашифрованных столбцов. Поставщик данных .NET Framework для SQL Server взаимодействует с хранилищем ключей с помощью поставщика хранилища главных ключей столбцов, который является экземпляром класса, производным от класса SqlColumnEncryptionKeyStoreProvider.

Процедура получения ключа шифрования столбца:

  1. Если Always Encrypted включено для запроса, поставщик данных .NET Framework для SQL Server прозрачно вызывает sys.sp_describe_parameter_encryption , чтобы получить метаданные шифрования для параметров, предназначенных для зашифрованных столбцов, если запрос содержит параметры. Для зашифрованных данных, содержащихся в результатах запроса, SQL Server автоматически присоединяет метаданные шифрования. Сведения о главном ключе столбца включают в себя следующее:

    • Имя поставщика хранилища ключей, который инкапсулирует хранилище ключей, содержащее главный ключ столбца.
    • Путь к ключу, указывающий положение главного ключа столбца в хранилище ключей.

    Сведения о ключе шифрования столбца включают в себя следующее:

    • Зашифрованное значение ключа шифрования столбца.
    • Имя алгоритма, который использовался для шифрования ключа шифрования столбца.
  2. Поставщик данных .NET Framework для SQL Server использует имя поставщика хранилища главных ключей столбцов для поиска объекта поставщика (экземпляр класса, производного от класса SqlColumnEncryptionKeyStoreProvider) во внутренней структуре данных.

  3. Чтобы расшифровать ключ шифрования столбца, поставщик данных .NET Framework для SQL Server вызывает метод SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey, передавая путь к главному ключу столбца, зашифрованное значение ключа шифрования столбца и имя алгоритма шифрования, используемого для создания ключа шифрования зашифрованных столбцов.

Использование встроенных поставщиков хранилища главных ключей столбцов

В состав поставщика данных .NET Framework для SQL Server входят следующие встроенные поставщики хранилища главных ключей столбцов, которые предварительно зарегистрированы с конкретными именами поставщиков (используемыми для поиска поставщика).

Класс Description Имя поставщика
Класс SqlColumnEncryptionCertificateStoreProvider Поставщик для хранилища сертификатов Windows. MSSQL_CERTIFICATE_STORE
Класс SqlColumnEncryptionCngProvider

Примечание. Этот поставщик доступен в .NET Framework 4.6.1 или более поздней версии.
Поставщик хранилища ключей, поддерживающий Microsoft Cryptography API: Next Generation (CNG) API. Как правило, такое хранилище представляет собой аппаратный модуль безопасности — физическое устройство, которое защищает цифровые ключи и управляет ими, а также обеспечивает обработку шифрования. MSSQL_CNG_STORE
Класс SqlColumnEncryptionCspProvider

Примечание. Этот поставщик доступен в .NET Framework 4.6.1 или более поздней версии.
Поставщик хранилища ключей, поддерживающий Microsoft Cryptography API (CAPI). Как правило, такое хранилище представляет собой аппаратный модуль безопасности — физическое устройство, которое защищает цифровые ключи и управляет ими, а также обеспечивает обработку шифрования. MSSQL_CSP_PROVIDER

Вам не нужно вносить изменения в код приложения для использования этих поставщиков, но обратите внимание на следующее:

  • Вы (или ваш администратор баз данных) должны проверить правильность имени поставщика, настроенного в метаданных главного ключа столбца, и убедиться, что путь к ключу главного ключа столбца соответствует формату пути к ключу, который является допустимым для данного поставщика. Для настройки ключей мы рекомендуем использовать специальные средства, например средство SQL Server Management Studio, которое при выполнении инструкции CREATE COLUMN MASTER KEY (Transact-SQL) автоматически создает допустимые имена поставщиков и пути к ключам. Дополнительные сведения см. в разделах Configuring Always Encrypted using SQL Server Management Studio (Настройка Always Encrypted с помощью среды SQL Server Management Studio ) и Настройка постоянного шифрования с помощью PowerShell.
  • Убедитесь, что приложение может получить доступ к ключу в хранилище ключей. Для этого может потребоваться предоставить приложению доступ к ключу или хранилищу ключей (в зависимости от хранилища ключей) или выполнить другие действия по настройке конкретного хранилища ключей. Например, чтобы получить доступ к хранилищу ключей, реализующим CNG или CAPI (например, аппаратный модуль безопасности), необходимо убедиться, что на компьютере приложения установлена библиотека, реализуемая CNG или CAPI для вашего хранилища. Дополнительные сведения см. в разделе Создание и хранение главных ключей столбцов для Always Encrypted.

Использование поставщика хранилища ключей Azure

Хранилище ключей Azure удобно для хранения главных ключей столбцов для постоянного шифрования, особенно в том случае, если приложения размещены в Azure. Поставщик данных .NET Framework для SQL Server не включает встроенный поставщик хранилища главных ключей столбцов для Azure Key Vault, но он доступен как пакет NuGet, который можно легко интегрировать с приложением. Подробная информация доступна в следующих статьях:

Реализация настраиваемого поставщика хранилища главных ключей столбцов

Если вы хотите сохранить главные ключи столбцов в хранилище ключей, которое не поддерживается существующим поставщиком, можно реализовать настраиваемый поставщик, расширив класс SqlColumnEncryptionCngProvider и зарегистрировав поставщика с помощью метода SqlConnection.RegisterColumnEncryptionKeyStoreProviders.

public class MyCustomKeyStoreProvider : SqlColumnEncryptionKeyStoreProvider
    {
        public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] columnEncryptionKey)
        {
            // Logic for encrypting a column encrypted key.
        }
        public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm, byte[] EncryptedColumnEncryptionKey)
        {
            // Logic for decrypting a column encrypted key.
        }
    }  
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary\<string, SqlColumnEncryptionKeyStoreProvider> providers =
               new Dictionary\<string, SqlColumnEncryptionKeyStoreProvider>();
            providers.Add("MY_CUSTOM_STORE", customProvider);
            SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
            providers.Add(SqlColumnEncryptionCertificateStoreProvider.ProviderName, customProvider);
            SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers); 
	   // ...
        }

    }

Использование поставщиков хранилищ главных ключей столбцов для программной подготовки ключей

При доступе к зашифрованным столбцам поставщик данных .NET Framework для SQL Server прозрачно находит и вызывает нужный поставщик хранилища главных ключей столбцов, чтобы расшифровать ключи шифрования столбцов. Как правило, обычный код приложения не вызывает поставщики хранилища главных ключей напрямую. Однако можно создать и явным образом вызвать поставщик для программной подготовки ключей Always Encrypted и управления ими: для создания ключа шифрования зашифрованного столбца и расшифровки ключа шифрования столбца (например, в ходе смены главного ключа столбца). Дополнительные сведения см. в разделе Общие сведения об управлении ключами для Always Encrypted. Реализация собственных средств управления ключами может потребоваться только в том случае, если используется настраиваемый поставщик хранилища ключей. При использовании ключей, хранящихся в хранилище ключей Azure или в другом хранилище ключей, для которого существует встроенный поставщик, вы можете применять для управления ключами и подготовки ключей любые существующие средства, в том числе SQL Server Management Studio или PowerShell. В примере ниже показано создание ключа шифрования столбца и использование класса SqlColumnEncryptionCertificateStoreProvider для шифрования ключа с помощью сертификата.

using System.Security.Cryptography;
static void Main(string[] args)
{
    byte[] EncryptedColumnEncryptionKey = GetEncryptedColumnEncryptonKey(); 
    Console.WriteLine("0x" + BitConverter.ToString(EncryptedColumnEncryptionKey).Replace("-", "")); 
    Console.ReadKey();
}

static byte[]  GetEncryptedColumnEncryptonKey()
{
    int cekLength = 32;
    String certificateStoreLocation = "CurrentUser";
    String certificateThumbprint = "698C7F8E21B2158E9AED4978ADB147CF66574180";
    // Generate the plaintext column encryption key.
    byte[] columnEncryptionKey = new byte[cekLength];
    RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
    rngCsp.GetBytes(columnEncryptionKey);

    // Encrypt the column encryption key with a certificate.
    string keyPath = String.Format(@"{0}/My/{1}", certificateStoreLocation, certificateThumbprint);
    SqlColumnEncryptionCertificateStoreProvider provider = new SqlColumnEncryptionCertificateStoreProvider();
    return provider.EncryptColumnEncryptionKey(keyPath, @"RSA_OAEP", columnEncryptionKey); 
}

Управление влиянием постоянного шифрования на производительность

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

  • Дополнительные обращения к базе данных для получения метаданных для параметров запроса.
  • Вызовы хранилища главных ключей столбцов для доступа к главному ключу столбца.

В этом разделе описываются процессы оптимизации производительности, встроенные в поставщик .NET Framework для SQL Server, и способы управления влиянием двух указанных выше факторов на производительность.

Управление обращениями для получения метаданных для параметров запроса

Если для соединения включена функция Always Encrypted, по умолчанию поставщик данных .NET Framework для SQL Server будет вызывать sys.sp_describe_parameter_encryption для каждого параметризованного запроса, передавая инструкцию запроса (без значений параметров) в SQL Server. sys.sp_describe_parameter_encryption анализирует инструкцию запроса и для каждого параметра, который должен быть зашифрован, возвращает связанные с шифрованием сведения, позволяющие поставщику данных .NET Framework для SQL Server шифровать значения параметров. Описанное выше поведение обеспечивает высокий уровень прозрачности для клиентского приложения. Пока значения, предназначенные для зашифрованных столбцов, передаются поставщику данных .NET Framework для SQL Server в объектах SqlParameter, приложению (и разработчику приложений) не требуется знать, какие запросы получают доступ к зашифрованным столбцам.

Кэширование метаданных запроса

В платформе .NET Framework 4.6.2 и более поздней версии поставщик данных .NET Framework для SQL Server кэширует результаты sys.sp_describe_parameter_encryption для каждой инструкции запроса. Таким образом, если одна и та же инструкция запроса выполняется несколько раз, драйвер вызывает sys.sp_describe_parameter_encryption всего один раз. Кэширование метаданных шифрования для инструкций запроса значительно сокращает затраты ресурсов на получение метаданных из базы данных. Кэширование включено по умолчанию. Можно отключить параметр кэширования метаданных, задав для SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled свойство значение false, однако рекомендуется делать это только в редких случаях, например в описанной ниже ситуации:

Рассмотрим базу данных с двумя схемами s1 и s2. Каждая из этих схем содержит таблицу с именем t. Определения таблиц s1.t и s2.t идентичны, за исключением свойств, связанных с шифрованием: столбец c в таблице s1.t не шифруется, однако зашифрован в таблице s2.t. База данных имеет двух пользователей: u1 и u2. Для пользователя u1 указана схема по умолчанию s1. Для u2 указана схема по умолчанию s2. Приложение .NET открывает два подключения к базе данных, олицетворяя пользователя u1 в одном из них и пользователя u2 в другом. Приложение отправляет запрос с параметром, предназначенным для c столбца по подключению для пользователя u1 (запрос не указывает схему, поэтому предполагается схема пользователя по умолчанию). Затем приложение отправляет тот же запрос через подключение для пользователя u2. Если кэширование метаданных запроса включено, после первого запроса кэш будет заполнен метаданными, указывающими c на столбец, целевые объекты параметров запроса не шифруются. Так как второй запрос такую же инструкцию запроса, используются сведения, хранящиеся в кэше. В результате драйвер отправит запрос без шифрования параметра (неправильного, так как целевой столбец s2.t.c зашифрован), утечки значения открытого текста параметра на сервер. Сервер обнаружит несоответствие и велит драйверу обновить кэш, чтобы приложение могло прозрачно переотправить запрос с правильно зашифрованным значением параметра. В этом случае следует отключить кэширование во избежание утечки конфиденциальных значений на сервер.

Задание постоянного шифрования на уровне запроса

Для управления влиянием процесса получения метаданных шифрования для параметризованных запросов на производительность можно включить постоянное шифрование для отдельных запросов, а не настраивать его для соединения. Таким образом, это гарантирует, что sys.sp_describe_parameter_encryption вызывается только для запросов, которые точно имеют параметры, предназначенные для зашифрованных столбцов. Обратите внимание, что в этом случае снижается прозрачность шифрования: при изменении свойств шифрования столбцов базы данных может потребоваться изменить код приложения в соответствии с изменениями схемы.

Заметка

Настройка Always Encrypted на уровне запроса дает ограниченный выигрыш в производительности для платформы .NET 4.6.2 и более поздних версий, где реализовано кэширование метаданных шифрования параметра.

Для управления поведением функции Always Encrypted в отдельных запросах необходимо использовать этот конструктор SqlCommand и SqlCommandColumnEncryptionSetting. Ниже приведены некоторые полезные рекомендации.

  • Если большинство запросов клиентское приложение отправляет зашифрованные столбцы для подключения к базе данных:
    • Задайте для ключевого слова строки подключения Параметр шифрования столбца значение Включено.
    • Задайте sqlCommandColumnEncryptionSetting.Disabled для отдельных запросов, которые не обращаются к зашифрованным столбцам. В этом варианте отключается возможность вызова sys.sp_describe_parameter_encryption и расшифровки значений в наборе результатов.
    • Задайте sqlCommandColumnEncryptionSetting.ResultSet для отдельных запросов, которые не имеют параметров, требующих шифрования, но извлеките данные из зашифрованных столбцов. В этом варианте отключается возможность вызова sys.sp_describe_parameter_encryption и шифрования параметров. Запрос сможет расшифровывать результаты из столбцов шифрования.
  • Если большинство запросов, которые клиентское приложение отправляет через подключение к базе данных, не обращается к зашифрованным столбцам:
    • Задайте для ключевого слова строки подключения Параметр шифрования столбца значение Отключено.
    • Задайте SqlCommandColumnEncryptionSetting.Enabled для отдельных запросов, имеющих параметры, которые требуется зашифровать. В этом варианте включается возможность вызова sys.sp_describe_parameter_encryption и расшифровки результатов запроса, полученных из зашифрованных столбцов.
    • Задайте SqlCommandColumnEncryptionSetting.ResultSet для запросов, которые не имеют параметров, требующих шифрования, но получают данные из зашифрованных столбцов. В этом варианте отключается возможность вызова sys.sp_describe_parameter_encryption и шифрования параметров. Запрос сможет расшифровывать результаты из столбцов шифрования.

В следующем примере постоянное шифрование отключено для подключения к базе данных. Запрос, который возникает в приложении, имеет параметр, предназначенный для столбца LastName, который не зашифрован. Запрос получает данные из зашифрованных столбцов SSN и BirthDate. В этом случае вызывать sys.sp_describe_parameter_encryption для получения метаданных шифрования не требуется. Однако необходимо включить расшифровку результатов запроса, чтобы приложение могло получать значения в виде обычного текста из двух зашифрованных столбцов. Для этого используется параметр SqlCommandColumnEncryptionSetting.ResultSet.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand cmd = new SqlCommand(@"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName]=@LastName",
connection, null, SqlCommandColumnEncryptionSetting.ResultSetOnly))
    {
        SqlParameter paramLastName = cmd.CreateParameter();
        paramLastName.ParameterName = @"@LastName";
        paramLastName.DbType = DbType.String;
        paramLastName.Direction = ParameterDirection.Input;
        paramLastName.Value = "Abel";
        paramLastName.Size = 50;
        cmd.Parameters.Add(paramLastName);
        using (SqlDataReader reader = cmd.ExecuteReader())
            {
               if (reader.HasRows)
               {
                  while (reader.Read())
                  {
                     Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2], ((DateTime)reader[3]).ToShortDateString());
                  }
               }
            }
  } 
}

Кэширование ключа шифрования столбца

Чтобы уменьшить количество вызовов к хранилищу главных ключей столбцов для расшифровки ключей шифрования столбцов, поставщик данных .NET Framework для SQL Server кэширует ключи шифрования столбцов с открытым текстом в памяти. После получения значения ключа шифрования зашифрованного столбца метаданных базы данных драйвер сначала пытается найти ключ шифрования столбца с открытым текстом, соответствующий зашифрованному значению ключа. Драйвер вызывает хранилище ключей, содержащее главный ключ столбца, только если он не может найти значение ключа шифрования зашифрованного столбца в кэше.

Заметка

В платформе .NET Framework 4.6 и 4.6.1 записи ключей шифрования столбцов в кэше никогда не удаляются. Это означает, что для данного ключа шифрования зашифрованного столбца драйвер обращается в хранилище ключей только один раз за все время существования приложения.

В платформе .NET Framework 4.6.2 и более поздних версий записи кэша удаляются по истечении настроенного срока жизни из соображений безопасности. Значение по умолчанию для срока жизни составляет 2 часа. Если у вас действуют более строгие требования к безопасности, касающиеся времени кэширования ключей шифрования столбца в виде открытого текста в приложении, это значение можно изменить с помощью свойства SqlConnection.ColumnEncryptionKeyCacheTtl.

Включение дополнительной защиты для скомпрометированного SQL Server

По умолчанию поставщик данных .NET Framework для SQL Server полагается на систему базы данных (SQL Server или Базу данных SQL Azure), которая предоставляет метаданные о том, какие столбцы базы данных шифруются и как именно. Метаданные шифрования позволяют поставщику данных .NET Framework для SQL Server шифровать параметры запроса и расшифровывать результаты запроса без получения дополнительных входных данных из приложения, что позволяет значительно сократить число изменений, необходимых для приложения. Однако если процесс SQL Server скомпрометирован и злоумышленник незаконно изменяет метаданные, которые SQL Server отправляет поставщику данных платформы .NET Framework для SQL Server, злоумышленник получает возможность украсть конфиденциальную информацию. В этом разделе описываются API-интерфейсы, которые помогают обеспечить дополнительный уровень защиты от таких атак за счет снижения прозрачности.

Принудительное шифрование параметров

Прежде чем поставщик данных .NET Framework для SQL Server отправляет параметризованный запрос в SQL Server, он просит SQL Server (путем вызова sys.sp_describe_parameter_encryption) проанализировать инструкцию запроса и предоставить сведения о том, какие параметры запроса должны быть зашифрованы. Скомпрометированный экземпляр SQL Server может неправильно использовать поставщик данных .NET Framework для SQL Server, отправив метаданные, указывающие, что параметр не предназначен для зашифрованного столбца, даже если столбец зашифрован в базе данных. В результате поставщик данных .NET Framework для SQL Server не зашифрует значение параметра, и он отправит его в виде обычного текста в скомпрометированный экземпляр SQL Server.

Чтобы предотвратить подобную атаку, приложение может присвоить свойству SqlParameter.ForceColumnEncryption для параметра значение true. Это приведет к возникновению исключения поставщиком данных .NET Framework для SQL Server, если метаданные, полученные от сервера, указывают на то, что параметр не должен быть зашифрован.

Хотя использование свойства SqlParameter.ForceColumnEncryption помогает повысить безопасность, оно также снижает прозрачность шифрования для клиентского приложения. Если вы обновляете схему базы данных для изменения набора зашифрованных столбцов, вам может потребоваться изменить и само приложение.

В следующем примере кода показано, как с помощью свойства SqlParameter.ForceColumnEncryption предотвратить отправку номеров социального страхования в базу данных в формате открытого текста.

SqlCommand cmd = _sqlconn.CreateCommand(); 

// Use parameterized queries to access Always Encrypted data. 
 
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN] = @SSN;"; 

SqlParameter paramSSN = cmd.CreateParameter(); 
paramSSN.ParameterName = @"@SSN"; 
paramSSN.DbType = DbType.AnsiStringFixedLength; 
paramSSN.Direction = ParameterDirection.Input; 
paramSSN.Value = ssn; 
paramSSN.Size = 11; 
paramSSN.ForceColumnEncryption = true; 
cmd.Parameters.Add(paramSSN); 

SqlDataReader reader = cmd.ExecuteReader();

Настройка путей главного ключа доверенного столбца

Метаданные шифрования, возвращаемые SQL Server для параметров запроса, предназначенных для зашифрованных столбцов, и результатов, полученных из зашифрованных столбцов, включают в себя путь к главному ключу столбца, определяющий хранилище ключей и расположение ключа в этом хранилище. Если экземпляр SQL Server скомпрометирован, он может отправить путь к ключу, указывающий на поставщик данных .NET Framework для SQL Server в расположении, контролируемом злоумышленником. Это может привести к утечке учетных данных хранилища ключей, если оно запрашивает у приложение прохождение проверки подлинности.

Для предотвращения подобных атак приложение может задать список доверенных путей для отдельного сервера с помощью свойства SqlConnection.ColumnEncryptionTrustedMasterKeyPaths. Если поставщик данных платформы.NET для SQL Server получает путь, не входящий в доверенный список, он выдает исключение.

Хотя настройка доверенных путей ключей повышает безопасность приложения, вам потребуется изменить код или /и конфигурацию приложения при смене главного ключа столбца (при изменении пути главного ключа столбца).

В следующем примере показано, как настраивать доверенные пути к главному ключу столбца:

// Configure trusted key paths to protect against fake key paths sent by a compromised SQL Server instance 
// First, create a list of trusted key paths for your server 
List<string> trustedKeyPathList = new List<string>(); 
trustedKeyPathList.Add("CurrentUser/my/425CFBB9DDDD081BB0061534CE6AB06CB5283F5Ea"); 

// Register the trusted key path list for your server 

SqlConnection.ColumnEncryptionTrustedMasterKeyPaths.Add(serverName, trustedKeyPathList);

Копирование зашифрованных данных с помощью SqlBulkCopy

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

  • Убедитесь, что конфигурация шифрования целевой таблицы идентична конфигурации исходной таблицы. В частности, обе таблицы должны иметь одинаковые зашифрованные столбцы, которые должны быть зашифрованы с помощью одних и тех же типов шифрования и ключей шифрования. Примечание. Если любой из целевых столбцов шифруется не так, как соответствующий исходный столбец, вы не сможете расшифровать данные в целевой таблице после операции копирования. Данные будут повреждены.
  • Настройте подключения базы данных к исходной и целевой таблицам без включения постоянного шифрования.
  • Задайте параметр AllowEncryptedValueModifications (см. раздел SqlBulkCopyOptions). Примечание. Используйте осторожность при указании AllowEncryptedValueModifications, так как это может привести к повреждению базы данных, так как поставщик данных .NET Framework для SQL Server не проверяет, зашифрованы ли данные действительно или правильно зашифрованы с использованием того же типа шифрования, алгоритма и ключа, что и целевой столбец.

Параметр AllowEncryptedValueModifications доступен в .NET Framework 4.6.1 и более поздних версиях.

Ниже приведен пример копирования данных из одной таблицы в другую. Предполагается, что столбцы SSN и BirthDate зашифрованы.

static public void CopyTablesUsingBulk(string sourceTable, string targetTable)
{
   string sourceConnectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";
   string targetConnectionString = "Data Source= server64; Initial Catalog=Clinic; Integrated Security=true";
   using (SqlConnection connSource = new SqlConnection(sourceConnectionString))
   {
      connSource.Open();
      using (SqlCommand cmd = new SqlCommand(string.Format("SELECT [PatientID], [SSN], [FirstName], [LastName], [BirthDate] FROM {0}", sourceTable), connSource))
      {
         using (SqlDataReader reader = cmd.ExecuteReader())
         {
            SqlBulkCopy copy = new SqlBulkCopy(targetConnectionString, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.AllowEncryptedValueModifications);
            copy.EnableStreaming = true;
            copy.DestinationTableName = targetTable;
            copy.WriteToServer(reader);
         }
      }
}

Справочник по API Always Encrypted

Пространство имен:System.Data.SqlClient

Сборка: System.Data (в System.Data.dll)

Наименование Описание Версия .NET
Класс SqlColumnEncryptionCertificateStoreProvider Поставщик хранилища ключей для хранилища сертификатов Windows. 4,6
Класс SqlColumnEncryptionCngProvider Поставщик хранилища ключей для интерфейса Microsoft Cryptography API: Next Generation (CNG). 4.6.1
Класс SqlColumnEncryptionCspProvider Поставщик хранилища ключей для Microsoft CAPI на основе поставщиков служб шифрования (CSP). 4.6.1
SqlColumnEncryptionKeyStoreProvider Базовый класс для всех поставщиков хранилища ключей. 4,6
Перечисление SqlCommandColumnEncryptionSetting Параметры для включения шифрования и расшифровки для подключения к базе данных. 4,6
Перечисление SqlCommandColumnEncryptionSetting Параметры для управления поведением постоянного шифрования для отдельных запросов. 4,6
Свойство SqlConnectionStringBuilder.ColumnEncryptionSetting Возвращает и задает постоянное шифрование в строке подключения. 4,6
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled свойство Включает и отключает кэширование метаданных для запроса шифрования. 4.6.2
свойства SqlConnection.ColumnEncryptionKeyCacheTtl Возвращает и задает срок жизни для записей в кэше ключа шифрования столбца. 4.6.2
свойства SqlConnection.ColumnEncryptionTrustedMasterKeyPaths Позволяет задать список доверенных путей ключа для сервера базы данных. Если при обработке запроса приложения драйвер получает путь ключа, которого нет в списке, произойдет сбой запроса. Это свойство обеспечивает дополнительную защиту от атак на систему безопасности, включающих предоставление скомпрометированным SQL Server фиктивных путей ключа, что может привести к утечке учетных данных хранилища ключей. 4,6
Метод SqlConnection.RegisterColumnEncryptionKeyStoreProviders Позволяет регистрировать пользовательские поставщики хранилища ключей. Это словарь, сопоставляющий имена поставщиков хранилища ключей с реализациями поставщиков хранилища ключей. 4,6
Конструктор SqlCommand (String, SqlConnection, SqlTransaction, SqlCommandColumnEncryptionSetting) Позволяет управлять поведением постоянного шифрования для отдельных запросов. 4,6
свойству SqlParameter.ForceColumnEncryption Принудительно шифрует параметр. Если SQL Server сообщает драйверу, что шифровать параметр необязательно, произойдет сбой запроса, использующего этот параметр. Это свойство обеспечивает дополнительную защиту от атак на систему безопасности, включающих предоставление клиенту скомпрометированным SQL Server неверных метаданных шифрования, что может привести к раскрытию данных. 4,6
Новое ключевое слово строки подключения : Column Encryption Setting=enabled Включает или отключает функцию постоянного шифрования для подключения. 4,6

См. также