Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Применимо к
- драйверам Майкрософт версии 5.8.0 для PHP для SQL Server
Введение
Always Encrypted с безопасными анклавами является второй итерацией функции Always Encrypted для SQL Server. Always Encrypted с безопасными анклавами позволяет выполнять сложные вычисления с зашифрованными данными путем создания безопасного анклава — области памяти на сервере, в которой зашифрованные данные в базе данных расшифровываются для выполнения вычислений. Поддерживаемые операции включают в себя сравнение и сопоставление шаблонов с использованием предложения LIKE.
Включение Always Encrypted с безопасными анклавами
Поддержка Always Encrypted с безопасными анклавами доступна в драйверах PHP для SQL Server начиная с версии 5.8.0. Для Always Encrypted с безопасными анклавами требуется SQL Server 2019 или более поздней версии и версия драйвера ODBC 17.4 и выше Общие требования для Always Encrypted с драйверами PHP для SQL Server доступны, см. в статье Использование Always Encrypted с драйверами PHP для SQL Server.
Always Encrypted с безопасными анклавами обеспечивает безопасность зашифрованных данных путем подтверждения анклава, то есть проверки анклава по отношению ко внешней службе аттестации. Чтобы использовать безопасные анклавы, ключевое слово ColumnEncryption должно обозначать тип аттестации и протокол вместе со связанными данными аттестации, разделенными запятыми. Версия 17.4 драйвера ODBC поддерживает только безопасность на основе виртуализации (VBS) и протокол службы защиты узла (HGS) для типа и протокола анклава. Связанные данные аттестации — это URL-адрес сервера аттестации. Таким образом, в строку подключения будет добавлен следующий параметр:
ColumnEncryption=VBS-HGS,http://attestationserver.mydomain/Attestation
Если протокол неверен, драйвер не сможет его распознать, произойдет сбой подключения и будет возвращена ошибка. Если неверен только URL-адрес аттестации, подключение будет установлено, а при попытке вычисления с поддержкой анклава возникнет ошибка. В противном случае поведение будет идентично исходному поведению функции Always Encrypted. Если для параметра ColumnEncryption выбрать значение enabled, будут реализованы обычные функции Always Encrypted, но при попытке выполнения операции с поддержкой анклава вернется ошибка.
Дополнительные сведения о настройке среды для поддержки Always Encrypted с безопасными анклавами, включая настройку службы защиты узла и создание необходимых ключей шифрования, см. в статье "Настройка и использование Always Encrypted с безопасными анклавами".
Примеры
Следующие примеры, один для SQLSRV и один для PDO_SQLSRV, создают таблицу с несколькими типами данных с открытым текстом, затем шифруют ее и выполняют сравнение и сопоставление шаблонов. Заметьте следующие детали:
- При шифровании таблицы с использованием
ALTER TABLEможно зашифровать только один столбец для каждого вызоваALTER TABLE, поэтому для шифрования нескольких столбцов требуется несколько вызовов. - При передаче порогового значения сравнения в качестве параметра для типов char и nchar ширина столбца должна быть указана в соответствующем параметре
SQLSRV_SQLTYPE_*или будет возвращена ошибкаHY104,Invalid precision value. - Для сопоставления шаблонов параметры сортировки должны быть указаны в виде
Latin1_General_BIN2с использованием предложенияCOLLATE. - При передаче строки сопоставления шаблонов в качестве параметра для совпадающих типов char и nchar константа
SQLSRV_SQLTYPE_*, переданная вsqlsrv_queryилиsqlsrv_prepare, должна указывать длину строки для сопоставления, а не размер столбца, так как типы char и nchar добавляют пробелы в конце строки. Например, при сопоставлении строки%abc%со столбцом типа char(10) укажитеSQLSRV_SQLTYPE_CHAR(5). Если вместо этого указатьSQLSRV_SQLTYPE_CHAR(10), запрос будет сопоставлять%abc%(с добавленными пятью пробелами), а все данные в столбце, содержащие менее пяти пробелов, не будут совпадать (поэтомуabcdefне будет соответствовать%abc%, так как в нем есть четыре пробела). Чтобы получить количество символов в строках Юникода, используйте функцииmb_strlenилиiconv_strlen. - Интерфейс PDO не позволяет указывать длину параметра. Вместо этого укажите длину 0 или
nullвPDOStatement::bindParam. Если для длины явно задано другое число, параметр рассматривается как выходной параметр. - Сопоставление шаблонов в Always Encrypted не работает с нестроковыми типами.
- Для ясности проверка ошибок исключена.
В обоих примерах используются следующие общие данные:
<?php
// Data for testing - integer, datetime2, char, nchar, varchar, and nvarchar
// String data is random, showing that we can match or compare anything
$testValues = array(array(1, "2019-12-31 01:00:00", "abcd", "㬚㔈♠既", "abcd", "㬚㔈♠既"),
array(-100, "1753-01-31 14:25:25.25", "#e@?q&zy+", "ઔܛ᎓Ե⅜", "#e@?q&zy+", "ઔܛ᎓Ե⅜"),
array(100, "2112-03-15 23:40:10.1594", "zyxwv", "㶋㘚ᐋꗡ", "zyxwv", "㶋㘚ᐋꗡ"),
array(0, "8888-08-08 08:08:08.08", "7t", "㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ", "7t", "㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ"),
);
// Queries to create the table and insert data
$createTable = "DROP TABLE IF EXISTS $myTable;
CREATE TABLE $myTable (c_integer int NULL,
c_datetime2 datetime2(7) NULL,
c_char char(32) NULL,
c_nchar nchar(32) NULL,
c_varchar varchar(32) NULL,
c_nvarchar nvarchar(32) NULL);";
$insertData = "INSERT INTO $myTable (c_integer, c_datetime2, c_char, c_nchar, c_varchar, c_nvarchar) VALUES (?, ?, ?, ?, ?, ?)";
// This is the query that encrypts the table in place
$encryptQuery = " ALTER TABLE $myTable
ALTER COLUMN [c_integer] integer
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER TABLE $myTable
ALTER COLUMN [c_datetime2] datetime2(7)
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER TABLE $myTable
ALTER COLUMN [c_char] char(32) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER TABLE $myTable
ALTER COLUMN [c_nchar] nchar(32) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER TABLE $myTable
ALTER COLUMN [c_varchar] varchar(32) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER TABLE $myTable
ALTER COLUMN [c_nvarchar] nvarchar(32) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK-enclave], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
WITH (ONLINE = ON);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;";
?>
SQLSRV
<?php
// Specify Azure Key Vault credentials using the KeyStoreAuthentication, KeyStorePrincipalId, and KeyStoreSecret keywords
// Otherwise, the local Windows Certificate Store will be used
$options = array('database'=>$myDatabase,
'uid'=>$myUsername,
'pwd'=>$myPassword,
'CharacterSet'=>'UTF-8',
'ReturnDatesAsStrings'=>true,
'ColumnEncryption'=>"VBS-HGS,http://myattestationserver.mydomain/Attestation",
);
$conn = sqlsrv_connect($myServer, $options);
// Create the table and insert the test data
$stmt = sqlsrv_query($conn, $createTable);
foreach ($testValues as $values) {
$stmt = sqlsrv_prepare($conn, $insertData, $values);
sqlsrv_execute($stmt);
}
// Encrypt the table in place
$stmt = sqlsrv_query($conn, $encryptQuery);
// Test comparison and pattern matching on the encrypted table
echo "Test comparisons:\n";
$intThreshold = 0;
$testGreater = "SELECT c_integer FROM $myTable WHERE c_integer > ?";
$param = array($intThreshold, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_INT);
$stmt = sqlsrv_prepare($conn, $testGreater, array($param));
getResults($stmt);
// Expect:
// 1
// 100
$datetimeThreshold = "3000-01-01 00:00:00.0";
$testLess = "SELECT c_datetime2 FROM $myTable WHERE c_datetime2 < ?";
$param = array($datetimeThreshold, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_DATETIME2);
$stmt = sqlsrv_prepare($conn, $testLess, array($param));
getResults($stmt);
// Expect:
// 2019-12-31 01:00:00.0000000
// 1753-01-31 14:25:25.2500000
// 2112-03-15 23:40:10.1594000
$charThreshold = "abcd";
$ncharThreshold = "㬚㔈♠既";
$testGreaterEqual = "SELECT c_char FROM $myTable WHERE c_char >= ?";
$param = array($charThreshold, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_CHAR(32));
$stmt = sqlsrv_prepare($conn, $testGreaterEqual, array($param));
getResults($stmt);
// Expect:
// abcd
// zyxwv
$testLessEqual = "SELECT c_nchar FROM $myTable WHERE c_nchar <= ?";
$param = array($ncharThreshold, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('UTF-8'), SQLSRV_SQLTYPE_NCHAR(32));
$stmt = sqlsrv_prepare($conn, $testLessEqual, array($param));
getResults($stmt);
// Expect:
// 㬚㔈♠既
// ઔܛ᎓Ե⅜
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
$testNotGreater = "SELECT c_varchar FROM $myTable WHERE c_varchar !> ?";
$param = array($charThreshold, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_VARCHAR);
$stmt = sqlsrv_prepare($conn, $testNotGreater, array($param));
getResults($stmt);
// Expect:
// abcd
// #e@?q&zy+
// 7t
$testNotLess = "SELECT c_nvarchar FROM $myTable WHERE c_nvarchar !< ?";
$param = array($ncharThreshold, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('UTF-8'), SQLSRV_SQLTYPE_NVARCHAR);
$stmt = sqlsrv_prepare($conn, $testNotLess, array($param));
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㶋㘚ᐋꗡ
echo "\nTest pattern matching:\n";
$charMatch = "%zy%";
$ncharMatch = "%㔈♠既%";
$param = array($charMatch, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_CHAR(strlen($charMatch)));
$testCharMatch = "SELECT c_char FROM $myTable WHERE c_char LIKE ? COLLATE Latin1_General_BIN2";
$stmt = sqlsrv_prepare($conn, $testCharMatch, array($param));
getResults($stmt);
// Expect:
// #e@?q&zy+
// zyxwv
$param = array($ncharMatch, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING("UTF-8"), SQLSRV_SQLTYPE_NCHAR(iconv_strlen($ncharMatch)));
$testNCharMatch = "SELECT c_nchar FROM $myTable WHERE c_nchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = sqlsrv_prepare($conn, $testNCharMatch, array($param));
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
$param = array($charMatch, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_VARCHAR(strlen($charMatch)));
$testVarcharMatch = "SELECT c_varchar FROM $myTable WHERE c_varchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = sqlsrv_prepare($conn, $testVarcharMatch, array($param));
getResults($stmt);
// Expect:
// #e@?q&zy+
// zyxwv
$param = array($ncharMatch, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING("UTF-8"), SQLSRV_SQLTYPE_NVARCHAR(iconv_strlen($ncharMatch)));
$testNVarcharMatch = "SELECT c_nvarchar FROM $myTable WHERE c_nvarchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = sqlsrv_prepare($conn, $testNVarcharMatch, array($param));
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
function getResults($stmt)
{
sqlsrv_execute($stmt);
while ($res = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) {
print_r($res[0]);
echo "\n";
}
}
?>
PDO_SQLSRV
<?php
// Specify Azure Key Vault credentials using the KeyStoreAuthentication, KeyStorePrincipalId, and KeyStoreSecret keywords
// Otherwise, the local Windows Certificate Store will be used
$options = "sqlsrv:server=$myServer;database=$myDatabase;driver={ODBC Driver 18 for SQL Server};";
$options .= "ColumnEncryption=VBS-HGS,http://myattestationserver.mydomain/Attestation",
$conn = new PDO($options, $myUsername, $myPassword);
// Create the table and insert the test data
$stmt = $conn->query($createTable);
foreach ($testValues as $values) {
$stmt = $conn->prepare($insertData);
$stmt->execute($values);
}
// Encrypt the table in place
$stmt = $conn->query($encryptQuery);
// Test comparison and pattern matching on the encrypted table
echo "Test comparisons:\n";
$intThreshold = 0;
$testGreater = "SELECT c_integer FROM $myTable WHERE c_integer > ?";
$stmt = $conn->prepare($testGreater);
$stmt->bindParam(1, $intThreshold, PDO::PARAM_INT);
getResults($stmt);
// Expect:
// 1
// 100
$datetimeThreshold = "3000-01-01 00:00:00.0";
$testLess = "SELECT c_datetime2 FROM $myTable WHERE c_datetime2 < ?";
$stmt = $conn->prepare($testLess);
$stmt->bindParam(1, $datetimeThreshold, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// 2019-12-31 01:00:00.0000000
// 1753-01-31 14:25:25.2500000
// 2112-03-15 23:40:10.1594000
$charThreshold = "abcd";
$ncharThreshold = "㬚㔈♠既";
$testGreaterEqual = "SELECT c_char FROM $myTable WHERE c_char >= ?";
$stmt = $conn->prepare($testGreaterEqual);
$stmt->bindParam(1, $charThreshold, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// abcd
// zyxwv
$testLessEqual = "SELECT c_nchar FROM $myTable WHERE c_nchar <= ?";
$stmt = $conn->prepare($testLessEqual);
$stmt->bindParam(1, $ncharThreshold, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// 㬚㔈♠既
// ઔܛ᎓Ե⅜
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
$testNotGreater = "SELECT c_varchar FROM $myTable WHERE c_varchar !> ?";
$stmt = $conn->prepare($testNotGreater);
$stmt->bindParam(1, $charThreshold, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// abcd
// #e@?q&zy+
// 7t
$testNotLess = "SELECT c_nvarchar FROM $myTable WHERE c_nvarchar !< ?";
$stmt = $conn->prepare($testNotLess);
$stmt->bindParam(1, $ncharThreshold, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㶋㘚ᐋꗡ
echo "\nTest pattern matching:\n";
$charMatch = "%zy%";
$ncharMatch = "%㔈♠既%";
$testCharMatch = "SELECT c_char FROM $myTable WHERE c_char LIKE ? COLLATE Latin1_General_BIN2";
$stmt = $conn->prepare($testCharMatch);
$stmt->bindParam(1, $charMatch, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// #e@?q&zy+
// zyxwv
$testNCharMatch = "SELECT c_nchar FROM $myTable WHERE c_nchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = $conn->prepare($testNCharMatch);
$stmt->bindParam(1, $ncharMatch, PDO::PARAM_STR,null,PDO::SQLSRV_ENCODING_UTF8);
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
$testVarcharMatch = "SELECT c_varchar FROM $myTable WHERE c_varchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = $conn->prepare($testVarcharMatch);
$stmt->bindParam(1, $charMatch, PDO::PARAM_STR);
getResults($stmt);
// Expect:
// #e@?q&zy+
// zyxwv
$testNVarcharMatch = "SELECT c_nvarchar FROM $myTable WHERE c_nvarchar LIKE ? COLLATE Latin1_General_BIN2";
$stmt = $conn->prepare($testNVarcharMatch);
$stmt->bindParam(1, $ncharMatch, PDO::PARAM_STR,null,PDO::SQLSRV_ENCODING_UTF8);
getResults($stmt);
// Expect:
// 㬚㔈♠既
// 㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
function getResults($stmt)
{
$stmt->execute();
while($res = $stmt->fetch(PDO::FETCH_NUM)) {
print_r($res[0]);
echo "\n";
}
}
?>
Выходные данные:
Test comparisons:
1
100
2019-12-31 01:00:00.0000000
1753-01-31 14:25:25.2500000
2112-03-15 23:40:10.1594000
abcd
zyxwv
㬚㔈♠既
ઔܛ᎓Ե⅜
㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
abcd
#e@?q&zy+
7t
㬚㔈♠既
㶋㘚ᐋꗡ
Test pattern matching:
#e@?q&zy+
zyxwv
㬚㔈♠既
㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
#e@?q&zy+
zyxwv
㬚㔈♠既
㛜ꆶ㕸㔈♠既ꁺꖁ㓫ޘ갧ᛄ
См. также
Руководство по программированию для драйвера SQL PHP
Справочник по API для драйвера SQLSRV
Справочник по API драйвера PDO_SQLSRV
Использование функции Always Encrypted с драйверами PHP для SQL Server