IIS环境下PHP连接启用Always Encrypted的Arabic_CI_AS数据库报错
问题描述
尝试访问启用Always Encrypted的SQL Server数据库时,IIS环境下运行PHP代码报错,但CMD环境下相同代码可正常执行,后续错误变更为“密钥集找不到”,疑似与数据库Arabic_CI_AS排序规则及加密后列的Arabic_BIN2排序规则兼容问题相关。
操作流程
- 在SQL Server中为目标表启用列加密;
- 数据库内验证:启用Always Encrypted后可正常返回解密数据;
- 编写PHP代码(如下);
- 运行代码报错,CMD环境下测试相同代码无异常。
<?php $hostname_DB= "localhost"; $database_DB= "test"; $username_DB= "***"; $password_DB= "***"; try { $connection = new PDO("sqlsrv:Server=$hostname_DB;Database=$database_DB;ColumnEncryption = Enabled;LoginTimeout=100000", $username_DB, $password_DB); $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $connection->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 1000000); $query="select TOP (10) second_name_a FROM employees"; $stmt = $connection->query($query); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { print_r($row);echo'<br>'; } } catch (PDOException $e) { die("Connection failed: " . $e->getMessage()); } ?>
错误信息
- 初始错误:
Connection failed: SQLSTATE[CE100]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The system cannot find the file specified.
- 更新后(2023/5/17)错误:
密钥集找不到
环境信息
- 运行环境:IIS(Internet Information Services)+PHP 8.0.6
- 已安装并启用Microsoft Drivers for PHP for SQL Server扩展:
php_pdo_sqlsrv_80_ts_x64.dll/php_sqlsrv_80_ts.dll
已尝试的无效操作
- 重启SQL Server
- 启用Named Pipes
- 检查用户连接权限
关键观察(更新信息)
- 2023/5/15:测试排序规则为
SQL_Latin1_General_CP1_CI_AS的数据库可正常运行,推测问题与Arabic_CI_AS排序规则有关,但无法转换该数据库排序规则;启用Always Encrypted后,列排序规则变为Arabic_BIN2,存在兼容问题。
解决方案建议
1. 修复IIS与CMD的权限差异问题
CMD运行正常但IIS报错,核心原因是IIS应用池身份无Always Encrypted密钥存储的访问权限:
- 打开IIS管理器,找到对应站点的应用池,查看其身份(默认是
ApplicationPoolIdentity或Network Service); - 若使用Windows证书存储:
- 打开
certlm.msc(本地计算机证书存储),找到Always Encrypted用的列主密钥证书; - 右键证书→所有任务→管理私钥;
- 添加应用池身份(格式为
IIS AppPool\你的应用池名称),授予读取权限;
- 打开
- 若使用Azure Key Vault等外部密钥存储,确保应用池身份拥有
Get、UnwrapKey等必要权限。
2. 处理排序规则兼容问题
针对Arabic_CI_AS数据库及Arabic_BIN2加密列的兼容问题:
- 升级ODBC Driver 17 for SQL Server至最新版本,旧版本对非拉丁排序规则的加密列支持有限;
- 在PHP连接字符串中显式指定数据库排序规则:
$connection = new PDO("sqlsrv:Server=$hostname_DB;Database=$database_DB;ColumnEncryption = Enabled;LoginTimeout=100000;ConnectionCollation=Arabic_CI_AS", $username_DB, $password_DB); - 验证密钥元数据状态:执行以下SQL确认列主密钥和列加密密钥正常启用:
SELECT name, is_enabled FROM sys.column_master_keys; SELECT name, is_enabled FROM sys.column_encryption_keys;
3. 排查“密钥集找不到”错误
该错误多与私钥访问权限或证书位置相关:
- 确认列主密钥证书存储在本地计算机存储(而非当前用户存储),IIS应用池身份默认无法访问当前用户的证书存储;
- 若证书为导入所得,确保导入时勾选“允许私钥被导出”(仅用于排查,生产环境可取消),且私钥未损坏;
- 运行
certutil -store My命令,检查本地计算机个人存储中的证书是否存在、私钥状态正常。
4. 其他排查步骤
- 启用ODBC驱动日志:打开ODBC数据源管理器(64位)→跟踪选项卡→勾选“启动ODBC跟踪”并设置日志路径,运行代码后查看日志定位具体失败点;
- 确认PHP扩展配置正确:确保
php.ini中启用的扩展版本与PHP 8.0.6 x64完全匹配,无32/64位扩展混用情况; - 测试基础连接:在IIS中运行无加密的简单查询,确认数据库基础连接正常,排除IIS本身配置问题。
内容的提问来源于stack exchange,提问作者Hesham Mahmoud
相关产品推荐
相关产品推荐

