Использование функции Always Encrypted с драйверами PHP для SQL ServerUsing Always Encrypted with the PHP Drivers for SQL Server

СкачатьСкачать драйвер PHPDownloadDownload PHP Driver

Применимо кApplicable to

  • Драйверы Майкрософт версии 5.2 для PHP для SQL ServerMicrosoft Drivers 5.2 for PHP for SQL Server

ВведениеIntroduction

В этой статье описано, как разрабатывать приложения PHP с помощью драйвера PHP Driver for SQL Server с Always Encrypted (ядро СУБД).This article provides information on how to develop PHP applications using Always Encrypted (Database Engine) and the PHP Drivers for SQL Server.

Функция Always Encrypted позволяет шифровать конфиденциальные данные в клиентских приложениях, не раскрывая данные или ключи шифрования для SQL Server или Базы данных SQL Azure.Always Encrypted allows client applications to encrypt sensitive data and never reveal the data or the encryption keys to SQL Server or Azure SQL Database. Драйвер с поддержкой Always Encrypted, такой как драйвер OLE DB для SQL Server, выполняет прозрачное шифрование и расшифровку конфиденциальных данных в клиентском приложении.An Always Encrypted enabled driver, such as the ODBC Driver for SQL Server, transparently encrypts and decrypts sensitive data in the client application. Драйвер автоматически определяет, какие параметры запроса соответствуют важным столбцам базы данных (защищенным с помощью Always Encrypted), и шифрует значения этих параметров перед передачей данных в SQL Server или Базу данных SQL Azure.The driver automatically determines which query parameters correspond to sensitive database columns (protected using Always Encrypted), and encrypts the values of those parameters before passing the data to SQL Server or Azure SQL Database. Аналогичным образом драйвер прозрачно расшифровывает данные, полученные из зашифрованных столбцов базы в результатах запроса.Similarly, the driver transparently decrypts data retrieved from encrypted database columns in query results. Дополнительные сведения см. в разделе Always Encrypted (ядро СУБД).For more information, see Always Encrypted (Database Engine). Драйверы PHP для SQL Server используют драйвер ODBC для SQL Server для шифрования конфиденциальных данных.The PHP Drivers for SQL Server utilize the ODBC Driver for SQL Server to encrypt sensitive data.

предварительные требованияPrerequisites

  • Настройте функцию постоянного шифрования в базе данных.Configure Always Encrypted in your database. В процесс настройки входят действия по подготовке ключей Always Encrypted и настройке шифрования для выбранных столбцов базы данных.This configuration involves provisioning Always Encrypted keys and setting up encryption for selected database columns. Если в базе данных постоянное шифрование еще не настроено, следуйте инструкциям в разделе Приступая к работе с постоянным шифрованием.If you do not already have a database with Always Encrypted configured, follow the directions in Getting Started with Always Encrypted. В частности база данных должна содержать определения метаданных для главного ключа столбца (CMK), ключа шифрования столбца (CEK) и таблицы с одним или несколькими столбцами, зашифрованными с помощью этого ключа CEK.In particular, your database should contain the metadata definitions for a Column Master Key (CMK), a Column Encryption Key (CEK), and a table containing one or more columns encrypted using that CEK.
  • Убедитесь, что на компьютере разработки установлен драйвер ODBC для SQL Server версии 17 или выше.Make sure ODBC Driver for SQL Server version 17 or higher is installed on your development machine. Дополнительные сведения см. в разделе драйвер ODBC для SQL Server.For details, see ODBC Driver for SQL Server.

Включение функции Always Encrypted в приложении PHPEnabling Always Encrypted in a PHP Application

Самым простым способом включения шифрования параметров для зашифрованных столбцов и расшифровки результатов запросов является установка для ключевого слова строки подключения ColumnEncryption значения Enabled.The easiest way to enable the encryption of parameters targeting the encrypted columns and the decryption of query results is by setting the value of the ColumnEncryption connection string keyword to Enabled. Ниже приведены примеры включения Always Encrypted в драйверах SQLSRV и PDO_SQLSRV.The following are examples of enabling Always Encrypted in the SQLSRV and PDO_SQLSRV drivers:

SQLSRV:SQLSRV:

$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, "ColumnEncryption"=>"Enabled");
$conn = sqlsrv_connect($server, $connectionInfo);

PDO_SQLSRV:PDO_SQLSRV:

$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled;";
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", $uid, $pwd);

Включенной функции Always Encrypted недостаточно для успешного шифрования или расшифровки. Вам нужно убедиться в следующем:Enabling Always Encrypted is not sufficient for encryption or decryption to succeed; you also need to make sure that:

  • Приложение имеет разрешения VIEW ANY COLUMN MASTER KEY DEFINITION и VIEW ANY COLUMN ENCRYPTION KEY DEFINITION для базы данных, необходимые для доступа к метаданным о ключах Always Encrypted в базе данных.The application has the VIEW ANY COLUMN MASTER KEY DEFINITION and VIEW ANY COLUMN ENCRYPTION KEY DEFINITION database permissions, required to access the metadata about Always Encrypted keys in the database. См. подробнее о разрешениях базы данных.For details, see Database Permission.
  • Приложение может обращаться к CMK для защиты ключей CEK для запрашиваемых зашифрованных столбцов.The application can access the CMK that protects the CEKs for the queried encrypted columns. Это требование зависит от поставщика хранилища ключей, в котором хранится CMK.This requirement is dependent on the key store provider that stores the CMK. См. подробнее о работе с хранилищами главных ключей столбцов.For more information, see Working with Column Master Key Stores.

Получение и изменение данных в зашифрованных столбцахRetrieving and Modifying Data in Encrypted Columns

После включения Always Encrypted для подключения можно использовать стандартные API SQLSRV (см. Справочник по API-интерфейсу sqlsrv) или PDO_SQLSRV API (см. Справочник по API драйвера PDO_SQLSRV) для получения или изменения данных в зашифрованных столбцах базы данных.Once you enable Always Encrypted on a connection, you can use standard SQLSRV APIs (see SQLSRV Driver API Reference) or PDO_SQLSRV APIs (see PDO_SQLSRV Driver API Reference) to retrieve or modify data in encrypted database columns. Если приложение имеет необходимые разрешения для базы данных и может обращаться к главному ключу столбца, драйвер будет шифровать все параметры запроса, затрагивающие зашифрованные столбцы, и расшифровывать данные, извлекаемые из зашифрованных столбцов. Для приложения это все выполняется незаметно, как если бы столбцы не были зашифрованы.Assuming your application has the required database permissions and can access the column master key, the driver encrypts any query parameters that target encrypted columns and decrypt data retrieved from encrypted columns, behaving transparently to the application as if the columns were not encrypted.

Если функция Always Encrypted не включена, выполнение запросов с параметрами, предназначенными для зашифрованных столбцов, завершится ошибкой.If Always Encrypted is not enabled, queries with parameters that target encrypted columns fail. Данные по-прежнему могут извлекаться из зашифрованных столбцов, пока для них не будут указаны параметры, предназначенные для зашифрованных столбцов.Data can still be retrieved from encrypted columns, as long as the query has no parameters targeting encrypted columns. При этом драйвер не будет применять расшифровку, и приложение будет получать двоичные зашифрованные данные (в виде массивов байтов).However, the driver does not attempt any decryption and the application receives the binary encrypted data (as byte arrays).

В приведенной ниже таблице описывается поведение запросов в зависимости от того, включена ли функция Always Encrypted:The following table summarizes the behavior of queries, depending on whether Always Encrypted is enabled or not:

Характеристика запросаQuery characteristic Постоянное шифрование включено, и приложение может получать доступ к ключам и метаданным ключейAlways Encrypted is enabled and application can access the keys and key metadata Постоянное шифрование включено, и приложение не может получать доступ к ключам и метаданным ключейAlways Encrypted is enabled and application cannot access the keys or key metadata Постоянное шифрование отключеноAlways Encrypted is disabled
Параметры, предназначенные для зашифрованных столбцов.Parameters targeting encrypted columns. Значения параметров прозрачно шифруются.Parameter values are transparently encrypted. ОшибкаError ОшибкаError
Извлечение данных из зашифрованных столбцов без параметров, предназначенных для зашифрованных столбцов.Retrieving data from encrypted columns, without parameters targeting encrypted columns. Результаты из зашифрованных столбцов прозрачно расшифровываются.Results from encrypted columns are transparently decrypted. Приложение получает значения столбца в виде обычного текста.The application receives plaintext column values. ОшибкаError Результаты из зашифрованных столбцов не расшифровываются.Results from encrypted columns are not decrypted. Приложение получает зашифрованные значения в виде массивов байтов.The application receives encrypted values as byte arrays.

В следующих примерах показано получение и изменение данных в зашифрованных столбцах.The following examples illustrate retrieving and modifying data in encrypted columns. В этом примере предполагается, что таблица имеет следующую схему.The examples assume a table with the following schema. Столбцы SSN и BirthDate зашифрованы.The SSN and BirthDate columns are encrypted.

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

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

В следующих примерах показано, как использовать драйверы SQLSRV и PDO_SQLSRV для вставки строки в таблицу пациента.The following examples demonstrate how to use the SQLSRV and PDO_SQLSRV drivers to insert a row into the Patient table. Обратите внимание на следующие моменты.Note the following points:

  • В образце кода нет ничего, связанного с шифрованием.There is nothing specific to encryption in the sample code. Драйвер автоматически обнаруживает и шифрует значения параметров SSN и BirthDate, которые предназначены для зашифрованных столбцов.The driver automatically detects and encrypts the values of the SSN and BirthDate parameters, which target encrypted columns. В этом случае шифрование является прозрачным для приложения.This mechanism makes encryption transparent to the application.
  • Значения, вставляемые в столбцы базы данных, включая зашифрованные столбцы, передаются как связанные параметры.The values inserted into database columns, including the encrypted columns, are passed as bound parameters. Несмотря на то, что при отправке значений в незашифрованные столбцы использовать параметры необязательно (но настоятельно рекомендуется, так как это помогает предотвратить внедрение кода SQL), они требуются для значений, предназначенных для зашифрованных столбцов.While using parameters is optional when sending values to non-encrypted columns (although it is highly recommended because it helps prevent SQL injection), it is required for values targeting encrypted columns. Если значения, вставленные в столбцы SSN или BirthDate, были переданы в качестве внедренных в инструкцию запроса литералов, выполнение запроса завершится ошибкой, так как драйвер не пытается шифровать или иным образом обрабатывать литералы в запросах.If the values inserted in the SSN or BirthDate columns were passed as literals embedded in the query statement, the query would fail because the driver does not attempt to encrypt or otherwise process literals in queries. В результате сервер отклонит их как несовместимые с зашифрованными столбцами.As a result, the server would reject them as incompatible with the encrypted columns.
  • При вставке значений с помощью параметров привязки тип SQL, идентичный типу данных целевого столбца, или, преобразование которого в тип данных целевого столбца поддерживается, должно передаваться в базу данных.When inserting values using bind parameters, a SQL type that is identical to the data type of the target column or whose conversion to the data type of the target column is supported must be passed to the database. Это требование обусловлено тем, что Always Encrypted поддерживает недостаточное число преобразований типов (Дополнительные сведения см. в разделе Always encrypted (ядро СУБД)).This requirement is because Always Encrypted supports few type conversions (for details, see Always Encrypted (Database Engine)). Два драйвера PHP, SQLSRV и PDO_SQLSRV, имеют механизм, помогающий пользователю определить тип значения SQL.The two PHP drivers, SQLSRV and PDO_SQLSRV, each has a mechanism to help the user determine the SQL type of the value. Таким образом, пользователю не нужно явно предоставлять тип SQL.Therefore, the user does not have to provide the SQL type explicitly.
  • Для драйвера SQLSRV пользователь имеет два варианта:For the SQLSRV driver, the user has two options:
  • Используйте драйвер PHP, чтобы определить и установить правильный тип SQL.Rely on the PHP driver to determine and set the right SQL type. В этом случае для выполнения параметризованного запроса пользователь должен использовать sqlsrv_prepare и sqlsrv_execute.In this case, the user must use sqlsrv_prepare and sqlsrv_execute to execute a parameterized query.
  • Явно задайте тип SQL.Set the SQL type explicitly.
  • Для драйвера PDO_SQLSRV пользователь не имеет возможности явно задавать тип SQL параметра.For the PDO_SQLSRV driver, the user does not have the option to explicitly set the SQL type of a parameter. Драйвер PDO_SQLSRV автоматически помогает пользователю определить тип SQL при привязке параметра.The PDO_SQLSRV driver automatically helps the user determine the SQL type when binding a parameter.
  • Чтобы драйверы определили тип SQL, применяются некоторые ограничения.For the drivers to determine the SQL type, some limitations apply:
  • Драйвер SQLSRV:SQLSRV Driver:
  • Если пользователь хочет, чтобы драйвер определил типы SQL для зашифрованных столбцов, пользователь должен использовать sqlsrv_prepare и sqlsrv_execute.If the user wants the driver to determine the SQL types for the encrypted columns, the user must use sqlsrv_prepare and sqlsrv_execute.
  • Если sqlsrv_query является предпочтительным, пользователь несет ответственность за указание типов SQL для всех параметров.If sqlsrv_query is preferred, the user is responsible for specifying the SQL types for all parameters. Указанный тип SQL должен включать длину строки для строковых типов, а также масштаб и точность для десятичных типов.The specified SQL type must include the string length for string types, and the scale and precision for decimal types.
  • Драйвер PDO_SQLSRV:PDO_SQLSRV Driver:
  • Атрибут инструкции PDO::SQLSRV_ATTR_DIRECT_QUERY не поддерживается в параметризованном запросе.The statement attribute PDO::SQLSRV_ATTR_DIRECT_QUERY is not supported in a parameterized query.
  • Атрибут инструкции PDO::ATTR_EMULATE_PREPARES не поддерживается в параметризованном запросе.The statement attribute PDO::ATTR_EMULATE_PREPARES is not supported in a parameterized query.

Драйвер SQLSRV и sqlsrv_prepare:SQLSRV driver and sqlsrv_prepare:

// insertion into encrypted columns must use a parameterized query
$query = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?)";
$ssn = "795-73-9838";
$firstName = "Catherine";
$lastName = "Abel;
$birthDate = "1996-10-19";
$params = array($ssn, $firstName, $lastName, $birthDate);
// during sqlsrv_prepare, the driver determines the SQL types for each parameter and pass them to SQL server
$stmt = sqlsrv_prepare($conn, $query, $params);
sqlsrv_execute($stmt);

Драйвер SQLSRV и sqlsrv_query:SQLSRV driver and sqlsrv_query:

// insertion into encrypted columns must use a parameterized query
$query = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?)";
$ssn = "795-73-9838";
$firstName = "Catherine";
$lastName = "Abel";
$birthDate = "1996-10-19";
// need to provide the SQL types for ALL parameters  
// note the SQL types (including the string length) have to be the same at the column definition
$params = array(array(&$ssn, null, null, SQLSRV_SQLTYPE_CHAR(11)),
                array(&$firstName, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)),
                array(&$lastName, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)),
                array(&$birthDate, null, null, SQLSRV_SQLTYPE_DATE));
sqlsrv_query($conn, $query, $params);

Драйверы PDO_SQLSRV и PDO::p готовка:PDO_SQLSRV driver and PDO::prepare:

// insertion into encrypted columns must use a parameterized query
$query = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?)";
$ssn = "795-73-9838";
$firstName = "Catherine";
$lastName = "Able";
$birthDate = "1996-10-19";
// during PDO::prepare, the driver determines the SQL types for each parameter and pass them to SQL server
$stmt = $conn->prepare($query);
$stmt->bindParam(1, $ssn);
$stmt->bindParam(2, $firstName);
$stmt->bindParam(3, $lastName);
$stmt->bindParam(4, $birthDate);
$stmt->execute();

Пример получения данных в виде открытого текстаPlaintext Data Retrieval Example

В следующих примерах демонстрируется фильтрация данных на основе зашифрованных значений и получение данных в виде открытого текста из зашифрованных столбцов с помощью драйверов SQLSRV и PDO_SQLSRV.The following examples demonstrate filtering data based on encrypted values, and retrieving plaintext data from encrypted columns using the SQLSRV and PDO_SQLSRV drivers. Обратите внимание на следующие моменты.Note the following points:

  • Значение, используемое в предложении WHERE для фильтрации по столбцу SSN, необходимо передавать, используя параметр bind, чтобы перед отправкой на сервер драйвер мог его прозрачно зашифровать.The value used in the WHERE clause to filter on the SSN column needs to be passed using bind parameter, so that the driver can transparently encrypt it before sending it to the server.
  • При выполнении запроса с привязанными параметрами драйверы PHP автоматически определяют тип SQL для пользователя, если только пользователь явно не указывает тип SQL при использовании драйвера SQLSRV.When executing a query with bound parameters, the PHP drivers automatically determines the SQL type for the user unless the user explicitly specifies the SQL type when using the SQLSRV driver.
  • Все значения, выводимые программой, будут представлены в открытом тексте, так как драйвер прозрачно расшифровывает данные, полученные из столбцов SSN и BirthDate.All values printed by the program are in plaintext, since the driver transparently decrypts the data retrieved from the SSN and BirthDate columns.

Примечание. Запросы могут выполнять сравнение на равенство для зашифрованных столбцов, только если используется детерминированное шифрование.Note: Queries can perform equality comparisons on encrypted columns only if the encryption is deterministic. Дополнительные сведения см. в разделе Выбор детерминированного или случайного шифрования.For more information, see Selecting Deterministic or Randomized encryption.

SQLSRV:SQLSRV:

// since SSN is an encrypted column, need to pass the value in the WHERE clause through bind parameter
$query = "SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN] = ?";
$ssn = "795-73-9838";
$stmt = sqlsrv_prepare($conn, $query, array(&$ssn));
// during sqlsrv_execute, the driver encrypts the ssn value and passes it to the database
sqlsrv_execute($stmt);
// fetch like usual
$row = sqlsrv_fetch_array($stmt);

PDO_SQLSRV:PDO_SQLSRV:

// since SSN is an encrypted column, need to pass the value in the WHERE clause through bind parameter
$query = "SELET [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN] = ?";
$ssn = "795-73-9838";
$stmt = $conn->prepare($query);
$stmt->bindParam(1, $ssn);
// during PDOStatement::execute, the driver encrypts the ssn value and passes it to the database
$stmt->execute();
// fetch like usual
$row = $stmt->fetch();

Пример получения данных в виде зашифрованного текстаCiphertext Data Retrieval Example

Если постоянное шифрование не включено, запрос может получать данные из зашифрованных столбцов, пока для него не будут указаны параметры, предназначенные для зашифрованных столбцов.If Always Encrypted is not enabled, a query can still retrieve data from encrypted columns, as long as the query has no parameters targeting encrypted columns.

В следующих примерах показано извлечение двоичных зашифрованных данных из зашифрованных столбцов с помощью драйверов SQLSRV и PDO_SQLSRV.The following examples illustrate retrieving binary encrypted data from encrypted columns using the SQLSRV and PDO_SQLSRV drivers. Обратите внимание на следующие моменты.Note the following points:

  • Так как постоянное шифрование не включено в строке подключения, запрос возвращает зашифрованные значения SSN и BirthD в виде байтовых массивов (программа преобразует значения в строки).As Always Encrypted is not enabled in the connection string, the query returns encrypted values of SSN and BirthDate as byte arrays (the program converts the values to strings).
  • Запрос, получающий данные из зашифрованных столбцов с отключенным постоянным шифрованием, может иметь параметры при условии, что ни один из параметров не предназначен для зашифрованного столбца.A query retrieving data from encrypted columns with Always Encrypted disabled can have parameters, as long as none of the parameters target an encrypted column. Приведенный ниже запрос выполняет фильтрацию по столбцу LastName, который не зашифрован в базе данных.The following query filters by LastName, which is not encrypted in the database. Запрос, отфильтрованный по SSN или BirthDate, завершится ошибкой.If the query filters by SSN or BirthDate, the query would fail.

SQLSRV:SQLSRV:

$query = "SELET [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName] = ?";
$lastName = "Abel";
$stmt = sqlsrv_prepare($conn, $query, array(&$lastName));
sqlsrv_execute($stmt);
$row = sqlsrv_fetch_array($stmt);

PDO_SQLSRV:PDO_SQLSRV:

$query = "SELET [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [LastName] = ?";
$lastName = "Abel";
$stmt = $conn->prepare($query);
$stmt->bindParam(1, $lastName);
$stmt->execute();
$row = $stmt->fetch();

Как избежать распространенных проблем при запросе зашифрованных столбцовAvoiding Common Problems when Querying Encrypted Columns

В этом разделе описываются общие категории ошибок, возникающих при выполнении запросов к зашифрованным столбцам из приложений PHP, и приводятся рекомендации о том, как их избежать.This section describes common categories of errors when querying encrypted columns from PHP applications and a few guidelines on how to avoid them.

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

Постоянное шифрование поддерживает несколько преобразований для зашифрованных типов данных.Always Encrypted supports few conversions for encrypted data types. Подробный список поддерживаемых преобразований типов см. в статье Always Encrypted (ядро СУБД).See Always Encrypted (Database Engine) for the detailed list of supported type conversions. Чтобы избежать ошибок при преобразовании типов данных, сделайте следующее:Do the following to avoid data type conversion errors:

  • При использовании драйвера SQLSRV с sqlsrv_prepare и sqlsrv_execute типа SQL вместе с размером столбца и числом десятичных разрядов параметра определяется автоматически.When using the SQLSRV driver with sqlsrv_prepare and sqlsrv_execute the SQL type, along with the column size and the number of decimal digits of the parameter is automatically determined.
  • При использовании драйвера PDO_SQLSRV для выполнения запроса тип SQL с размером столбца и числом десятичных разрядов параметра также определяется автоматическиWhen using the PDO_SQLSRV driver to execute a query, the SQL type with the column size and the number of decimal digits of the parameter is also automatically determined
  • При использовании драйвера SQLSRV с sqlsrv_query для выполнения запроса:When using the SQLSRV driver with sqlsrv_query to execute a query:
  • Тип SQL для параметра всегда точно совпадает с типом целевого столбца или может быть преобразован в тип этого столбца.The SQL type of the parameter is either exactly the same as the type of the targeted column, or the conversion from the SQL type to the type of the column is supported.
  • Точность и масштаб параметров, предназначенных для столбцов типов данных SQL Server decimal и numeric, соответствуют точности и масштабу, настроенным для конечного столбца.The precision and scale of the parameters targeting columns of the decimal and numeric SQL Server data types is the same as the precision and scale configure for the target column.
  • В запросах, которые изменяют конечный столбец, точность параметров, предназначенных для столбцов типов данных SQL Server datetime2, datetimeoffset или time, не превышает точность для конечного столбца.The precision of parameters targeting columns of datetime2, datetimeoffset, or time SQL Server data types is not greater than the precision for the target column, in queries that modify the target column.
  • Не используйте атрибуты инструкции PDO_SQLSRV PDO::SQLSRV_ATTR_DIRECT_QUERY или PDO::ATTR_EMULATE_PREPARES в параметризованном запросеDo not use PDO_SQLSRV statement attributes PDO::SQLSRV_ATTR_DIRECT_QUERY or PDO::ATTR_EMULATE_PREPARES in a parameterized query

Ошибки, возникающие из-за передачи значений в виде открытого текста, а не в зашифрованном видеErrors due to passing plaintext instead of encrypted values

Любое значение, предназначенное для зашифрованного столбца, должно быть зашифровано до отправки на сервер.Any value that targets an encrypted column needs to be encrypted before being sent to the server. Попытка вставки, изменения или фильтрации по значению, в виде открытого текста в зашифрованном столбце приведет к возникновению ошибки.An attempt to insert, modify, or filter by a plaintext value on an encrypted column results in an error. Чтобы избежать таких ошибок, убедитесь в том, что:To prevent such errors, make sure that:

  • Always Encrypted включен (в строке подключения задайте для ключевого слова ColumnEncryption значение Enabled).Always Encrypted is enabled (in the connection string, set the ColumnEncryption keyword to Enabled).
  • для отправки данных, предназначенных для зашифрованных столбцов, используется параметр bind.You use bind parameter to send data targeting encrypted columns. В следующем примере показан запрос, который неправильно фильтрует по литералу или константе в зашифрованном столбце (SSN):The following example shows a query that incorrectly filters by a literal/constant on an encrypted column (SSN):
$query = "SELET [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-73-9838'";

Управление влиянием постоянного шифрования на производительностьControlling Performance Impact of Always Encrypted

Так как Always Encrypted является технологией шифрования на стороне клиента, значительное влияние на производительность происходит на стороне клиента, а не в базе данных.Because Always Encrypted is a client-side encryption technology, most of the performance overhead is observed on the client side, not in the database. Помимо затрат на операции шифрования и расшифровки существуют и другие источники снижения производительности на стороне клиента:Apart from the cost of encryption and decryption operations, the other sources of performance overhead on the client side are:

  • дополнительные круговые пути к базе данных для получения метаданных для параметров запроса;Additional round-trips to the database to retrieve metadata for query parameters.
  • Вызовы хранилища главных ключей столбцов для доступа к главному ключу столбца.Calls to a column master key store to access a column master key.

круговые пути для получения метаданных для параметров запроса.Round-trips to Retrieve Metadata for Query Parameters

Если для соединения включена функция Always Encrypted, по умолчанию драйвер будет вызывать sys.sp_describe_parameter_encryption для каждого параметризованного запроса, передавая инструкцию запроса (без значений параметров) в SQL Server.If Always Encrypted is enabled for a connection, the ODBC Driver will, by default, call sys.sp_describe_parameter_encryption for each parameterized query, passing the query statement (without any parameter values) to SQL Server. Эта хранимая процедура анализирует инструкцию запроса и выясняет, нужно ли шифровать параметры. Если да, то она возвращает по каждому параметру связанные с шифрованием сведения, позволяющие драйверу шифровать их.This stored procedure analyzes the query statement to find out if any parameters need to be encrypted, and if so, returns the encryption-related information for each parameter to allow the driver to encrypt them.

Поскольку драйверы PHP позволяют пользователю привязать параметр в подготовленной инструкции без указания типа SQL, при привязке параметра в соединении с включенным Always Encrypted, драйверы PHP вызывают SQLDescribeParam для параметра, чтобы получить тип SQL, размер столбца и десятичные цифры.Since the PHP drivers allow the user to bind a parameter in a prepared statement without providing the SQL type, when binding a parameter in an Always Encrypted enabled connection, the PHP Drivers call SQLDescribeParam on the parameter to get the SQL type, column size, and decimal digits. Затем метаданные используются для вызова SQLBindParameter.The metadata is then used to call SQLBindParameter. Эти дополнительные SQLDescribeParam вызовы не потребовали дополнительных обращений к базе данных, так как драйвер ODBC уже сохранил информацию на стороне клиента при вызове sys.sp_describe_parameter_encryption.These extra SQLDescribeParam calls do not require extra round-trips to the database as the ODBC Driver has already stored the information on the client side when sys.sp_describe_parameter_encryption was called.

Такое поведение гарантирует для клиентского приложения высокий уровень прозрачности. Так как значения, предназначенные для зашифрованных столбцов, передаются драйверу в параметрах, приложению (и разработчику приложения) не нужно знать, какие запросы обращаются к зашифрованным столбцам.The preceding behaviors ensure a high level of transparency to the client application (and the application developer) does not need to be aware of which queries access encrypted columns, as long as the values targeting encrypted columns are passed to the driver in parameters.

В отличие от драйвера ODBC для SQL Server включение Always Encrypted на уровне инструкции или запроса пока не поддерживается в драйверах PHP.Unlike the ODBC Driver for SQL Server, enabling Always Encrypted at the statement/query-level is not yet supported in the PHP drivers.

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

Чтобы уменьшить количество вызовов к хранилищу главных ключей столбцов для расшифровки ключей шифрования столбцов (CEK), драйвер кэширует CEK в памяти в формате открытого текста.To reduce the number of calls to a column master key store to decrypt column encryption keys (CEK), the driver caches the plaintext CEKs in memory. Получив зашифрованные CEK (ECEK) из метаданных базы данных, драйвер ODBC сначала пытается найти в кэше CEK в соответствии с зашифрованным значением ключа.After receiving the encrypted CEK (ECEK) from database metadata, the ODBC driver first tries to find the plaintext CEK corresponding to the encrypted key value in the cache. Драйвер обращается к хранилищу ключей, где хранится главный ключ столбца, только в том случае, если ему не удается найти в кэше значение CEK в открытом тексте.The driver calls the key store containing the CMK only if it cannot find the corresponding plaintext CEK in the cache.

Примечание. Драйвер ODBC Driver for SQL Server удаляет записи из этого кэша через два часа.Note: In the ODBC Driver for SQL Server, the entries in the cache are evicted after a two-hour timeout. Это означает, что для каждого ECEK драйвер обращается в хранилище ключей только один раз за цикл жизни приложения либо каждые два часа в зависимости от того, что меньше.This behavior means that for a given ECEK, the driver contacts the key store only once during the lifetime of the application or every two hours, whichever is less.

Работа с хранилищами главных ключей столбцовWorking with Column Master Key Stores

Для шифрования или расшифровки данных драйвер должен получить ключ CEK, который настроен для целевого столбца.To encrypt or decrypt data, the driver needs to obtain a CEK that is configured for the target column. Ключи CEK хранятся в зашифрованном виде (ECEK) в метаданных базы данных.CEKs are stored in encrypted form (ECEKs) in the database metadata. Каждому ключу CEK соответствует определенный ключ CMK, который использовался для его шифрования.Each CEK has a corresponding CMK that was used to encrypt it. Метаданные базы данных не хранят значения CMK, а только имя хранилища ключей и информацию для поиска нужных CMK в этом хранилище ключей.The database metadata does not store the CMK itself; it only contains the name of the key store and information that the key store can use to locate the CMK.

Чтобы получить значение ECEK в формате открытого текста, драйвер сначала получает метаданные о ключах CEK и CMK, а затем на основе этих сведений обращается в хранилище ключей с CMK и запрашивает расшифрованную версию ECEK.To obtain the plaintext value of an ECEK, the driver first obtains the metadata about both the CEK and its corresponding CMK, and then it uses this information to contact the key store containing the CMK and requests it to decrypt the ECEK. Драйвер взаимодействует с хранилищем ключей через поставщик хранилища ключей.The driver communicates with a key store using a key store provider.

В Microsoft Driver 5.3.0 для PHP for SQL Server поддерживаются только поставщики хранилища сертификатов Windows и Azure Key Vault.For Microsoft Driver 5.3.0 for PHP for SQL Server, only Windows Certificate Store Provider and Azure Key Vault are supported. Другой поставщик хранилища ключей, поддерживаемый драйвером ODBC (пользовательский поставщик хранилища ключей), пока не поддерживается.The other Keystore Provider supported by the ODBC Driver (Custom Keystore Provider) is not yet supported.

Использование поставщика хранилища сертификатов WindowsUsing the Windows Certificate Store Provider

Драйвер ODBC Driver for SQL Server в Windows содержит встроенный поставщик MSSQL_CERTIFICATE_STORE хранилища сертификатов Windows для хранения главного ключа.The ODBC Driver for SQL Server on Windows includes a built-in column master key store provider for the Windows Certificate Store, named MSSQL_CERTIFICATE_STORE. (Этот поставщик недоступен для macOS и Linux.) При использовании этого поставщика ключи CMK хранятся локально на клиентском компьютере, и для работы с ним не нужно вносить никаких дополнительных изменений в конфигурацию приложения.(This provider is not available on macOS or Linux.) With this provider, the CMK is stored locally on the client machine and no additional configuration by the application is necessary to use it with the driver. Но такому приложению необходимы права доступа к сертификату и закрытому ключу, размещенным в хранилище.However, the application must have access to the certificate and its private key in the store. Дополнительные сведения см. в разделе Create and Store Column Master Keys (Always Encrypted)(Создание и хранение главных ключей столбцов (постоянное шифрование)).For more information, see Create and Store Column Master Keys (Always Encrypted).

Использование Azure Key VaultUsing Azure Key Vault

Azure Key Vault предлагает способ хранения ключей шифрования, паролей и других секретов с помощью Azure и может использоваться для хранения ключей для Always Encrypted.Azure Key Vault offers a way to store encryption keys, passwords, and other secrets using Azure and can be used to store keys for Always Encrypted. Драйвер ODBC для SQL Server (версии 17 и выше) включает встроенный поставщик хранилища главных ключей для Azure Key Vault.The ODBC Driver for SQL Server (version 17 and higher) includes a built-in master key store provider for Azure Key Vault. Следующие параметры соединения обработаны Azure Key Vault конфигурации: KeyStoreAuthentication, KeyStorePrincipalIdи KeyStoreSecret.The following connection options handle Azure Key Vault configuration: KeyStoreAuthentication, KeyStorePrincipalId, and KeyStoreSecret.

  • KeyStoreAuthentication может принимать одно из двух возможных строковых значений: KeyVaultPassword и KeyVaultClientSecret.KeyStoreAuthentication can take one of two possible string values: KeyVaultPassword and KeyVaultClientSecret. Эти значения определяют, какой тип учетных данных проверки подлинности используется с другими двумя ключевыми словами.These values control what kind of authentication credentials are used with the other two keywords.
  • KeyStorePrincipalId принимает строку, представляющую идентификатор для учетной записи, которая ищет доступ к Azure Key Vault.KeyStorePrincipalId takes a string representing an identifier for the account seeking to access the Azure Key Vault.
    • Если KeyStoreAuthentication имеет значение KeyVaultPassword, то KeyStorePrincipalId должно быть именем пользователя Azure ActiveDirectory.If KeyStoreAuthentication is set to KeyVaultPassword, then KeyStorePrincipalId must be the name of an Azure ActiveDirectory user.
    • Если KeyStoreAuthentication имеет значение KeyVaultClientSecret, то KeyStorePrincipalId должен быть ИДЕНТИФИКАТОРом клиента приложения.If KeyStoreAuthentication is set to KeyVaultClientSecret, then KeyStorePrincipalId must be an application client ID.
  • KeyStoreSecret принимает строку, представляющую секрет учетных данных.KeyStoreSecret takes a string representing a credential secret.
    • Если KeyStoreAuthentication имеет значение KeyVaultPassword, то KeyStoreSecret должен быть паролем пользователя.If KeyStoreAuthentication is set to KeyVaultPassword, then KeyStoreSecret must be the user's password.
    • Если KeyStoreAuthentication имеет значение KeyVaultClientSecret, то KeyStoreSecret должен быть секретом приложения, связанным с ИДЕНТИФИКАТОРом клиента приложения.If KeyStoreAuthentication is set to KeyVaultClientSecret, then KeyStoreSecret must be the application secret associated with the application client ID.

В строке подключения для использования Azure Key Vault должны присутствовать все три параметра.All three options must be present in the connection string to use Azure Key Vault. Кроме того, для ColumnEncryption необходимо задать значение Enabled.In addition, ColumnEncryption must be set to Enabled. Если ColumnEncryption имеет значение Disabled но есть параметры Azure Key Vault, скрипт продолжит работу без ошибок, но шифрование выполняться не будет.If ColumnEncryption is set to Disabled but the Azure Key Vault options are present, the script will proceed without errors but no encryption will be performed.

В следующих примерах показано, как подключиться к SQL Server с помощью Azure Key Vault.The following examples show how to connect to SQL Server using Azure Key Vault.

SQLSRV:SQLSRV:

Использование учетной записи Azure Active Directory:Using an Azure Active Directory account:

$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, "ColumnEncryption"=>"Enabled", "KeyStoreAuthentication"=>"KeyVaultPassword", "KeyStorePrincipalId"=>$AADUsername, "KeyStoreSecret"=>$AADPassword);
$conn = sqlsrv_connect($server, $connectionInfo);

С помощью идентификатора клиента приложения Azure и секрета:Using an Azure application client ID and secret:

$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, "ColumnEncryption"=>"Enabled", "KeyStoreAuthentication"=>"KeyVaultClientSecret", "KeyStorePrincipalId"=>$applicationClientID, "KeyStoreSecret"=>$applicationClientSecret);
$conn = sqlsrv_connect($server, $connectionInfo);

PDO_SQLSRV: использование учетной записи Azure Active Directory:PDO_SQLSRV: Using an Azure Active Directory account:

$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; KeyStoreAuthentication = KeyVaultPassword; KeyStorePrincipalId = $AADUsername; KeyStoreSecret = $AADPassword;";
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", $uid, $pwd);

С помощью идентификатора клиента приложения Azure и секрета:Using an Azure application client ID and secret:

$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; KeyStoreAuthentication = KeyVaultClientSecret; KeyStorePrincipalId = $applicationClientID; KeyStoreSecret = $applicationClientSecret;";
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", $uid, $pwd);

Ограничения драйвера PHP при использовании Always EncryptedLimitations of the PHP drivers when using Always Encrypted

SQLSRV и PDO_SQLSRV:SQLSRV and PDO_SQLSRV:

  • Linux и macOS не поддерживают поставщика хранилища сертификатов WindowsLinux/macOS do not support Windows Certificate Store Provider
  • Принудительное шифрование параметровForcing parameter encryption
  • Включение Always Encrypted на уровне инструкцииEnabling Always Encrypted at the statement level
  • При использовании функции Always Encrypted и национальных настроек, отличных от UTF8, в Linux и macOS (например, "en_US. ISO-8859-1 "), вставка данных null или пустой строки в зашифрованный столбец типа char (n) может не работать, если в системе не установлена кодовая страница 1252When using the Always Encrypted feature and non-UTF8 locales on Linux and macOS (such as "en_US.ISO-8859-1"), inserting null data or an empty string into an encrypted char(n) column may not work unless Code Page 1252 has been installed on your system

Только SQLSRV:SQLSRV only:

  • Использование sqlsrv_query для параметра привязки без указания типа SQLUsing sqlsrv_query for binding parameter without specifying the SQL type
  • Использование sqlsrv_prepare для привязки параметров в пакете инструкций SQLUsing sqlsrv_prepare for binding parameters in a batch of SQL statements

Только PDO_SQLSRV:PDO_SQLSRV only:

  • атрибут инструкции PDO::SQLSRV_ATTR_DIRECT_QUERY, указанный в параметризованном запросеPDO::SQLSRV_ATTR_DIRECT_QUERY statement attribute specified in a parameterized query
  • атрибут инструкции PDO::ATTR_EMULATE_PREPARE, указанный в параметризованном запросеPDO::ATTR_EMULATE_PREPARE statement attribute specified in a parameterized query
  • Привязка параметров в пакете инструкций SQLbinding parameters in a batch of SQL statements

Драйверы PHP также наследуют ограничения, установленные драйвером ODBC для SQL Server и базы данных.The PHP drivers also inherit the limitations imposed by the ODBC Driver for SQL Server and the database. См. раздел ограничения драйвера ODBC при использовании Always encrypted и Always encrypted подробных сведений о функциях.See Limitations of the ODBC driver when using Always Encrypted and Always Encrypted Feature Details.

См. также:See Also

Руководство по программированию для драйвера SQL PHP Справочник по API для драйвера SQLSRVProgramming Guide for PHP SQL Driver SQLSRV Driver API Reference
Справочник по API драйвера PDO_SQLSRVPDO_SQLSRV Driver API Reference