如何从经典 ASP 中读取 SQL 始终加密的列

How to read SQL Always-encrypted column from classic ASP

我维护着一个经典的 ASP 应用程序(是的,我知道,我们正在努力)并且需要在 SQL 2017 年访问 Always Encrypted 列。

我已经导入了证书并在 SSMS 和 PowerShell 中进行了测试,一切正常。我在 ASP 中所能做的最好的事情就是将加密值作为字节数组获取。我尝试过的连接字符串组合比我记得的还要多。 我的 ASP 开发箱是 Windows 10;数据服务器是 SQL 2017.

cnn = "Provider=MSOLEDBSQL; DataTypeCompatibility=80; " _
    & "DRIVER={ODBC Driver 17 for SQL Server}; " _
    & "SERVER=xxxx; UID=xxxxx; PWD=xxxxx; DATABASE=xxxx; " _
    & "ColumnEncryption=Enabled; Column Encryption Setting=Enabled;"
Set oDB = CreateObject( "ADODB.Connection" )
oDB.Open cnn
set oCmd = Server.CreateObject("ADODB.Command") 
oCmd.ActiveConnection = cnn
oCmd.CommandText = "SELECT top 10 ID, Enc FROM tbl1"
set rst = oCmd.Execute()

代码运行无误,但加密列 (Enc, varchar(50)) 作为字节数组返回。当我应该获取纯文本值时,我似乎正在获取加密值。我也试过调用具有相同结果的存储过程。查询中没有过滤器,因此无需参数化。 知道接下来要尝试什么吗?


答案:
1) 以与该 Web 应用程序的 AppPool Identity 相同的用户身份导入证书。
2) 将 Web 应用程序的匿名授权设置为应用程序池标识。
3) 使用此连接字符串:

  cnn = "Provider=MSDASQL;" _
      & "Extended Properties=""Driver={ODBC Driver 17 for SQL Server};" _
      & "SERVER=***; UID=***; PWD=***;" _
      & "DATABASE=***;ColumnEncryption=Enabled;"" "

用于 SQL 服务器的新 Microsoft OleDb 提供程序 (MSOLEDBSQL) 不支持 AlwaysEncrypted(当前)。您必须使用 ODBC,这意味着 OleDb 提供程序应该是 Microsoft OleDb Provider for ODBC (MSDASQL)。因此,您可以使用 Microsoft® ODBC 驱动程序 17 为 SQL 服务器配置系统 DSN,连接字符串如下:

cnn = "Provider=MSDASQL;DSN=testdb;"

或将所有 ODBC 驱动程序参数嵌入到 MSDASQL 连接字符串的 "Extended Properties" 中。喜欢

cnn = "Provider=MSDASQL;Extended Properties=""Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=testdb;Trusted_Connection=yes;ColumnEncryption=Enabled;"" "

这里是演练,首先使用 VBScript 进行测试,然后再使用 ASP 进行测试。

开始于:

create database testdb
go
use testdb

create table tbl1(id int, Enc varchar(200))

insert into tbl1(id,enc) values (1,'Hello')

然后 运行ning 通过 SSMS 中的列加密向导,为当前用户存储证书,机器上 运行ning SSMS:

然后query.vbs的列表:

cnn = "Provider=MSDASQL;Extended Properties=""Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=testdb;Trusted_Connection=yes;ColumnEncryption=Enabled;"" "
Set oDB = CreateObject( "ADODB.Connection" )
oDB.Open cnn
set oCmd = CreateObject("ADODB.Command") 
oCmd.ActiveConnection = cnn
oCmd.CommandText = "SELECT top 10 ID, Enc FROM tbl1"
set rst = oCmd.Execute()
rst.MoveFirst()
msgbox( cstr(rst("Enc")) )

可以从命令行 运行 使用:

cscript  .\query.vbs

要从 ASP 执行此操作,您还必须根据文档 here 将证书放入 IIS 应用程序池帐户的用户证书存储中。请注意,证书的相对路径必须对所有用户都相同。如果您最初将其配置为存储在用户的证书存储中,则无法将其存储在 IIS 机器上的机器存储中。 SQL 服务器存储密钥的 key_path 并指示客户端在哪里可以找到证书,例如 CurrentUser/my/388FF64065A96DCF0858D84A88E1ADB5A927DECE.

所以发现 Column Master Key 的密钥路径

select name, key_path from sys.column_master_keys

然后从拥有证书的机器上导出证书:

 PS C:\Windows> $path = "cert:\CurrentUser\My8FF64065A96DCF0858D84A88E1ADB5A927DECE"
 PS C:\Windows> $mypwd = ConvertTo-SecureString -String "xxxxxxx" -Force -AsPlainText
 PS C:\Windows> Export-PfxCertificate -Cert $path -FilePath c:\temp\myexport.pfx -ChainOption EndEntityCertOnly  -Password $mypwd

运行作为IIS服务器上的app pool identity用户,导入

PS C:\WINDOWS> $mypwd = ConvertTo-SecureString -String "xxxxxxx" -Force -AsPlainText
PS C:\WINDOWS> Import-PfxCertificate -FilePath C:\temp\myexport.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $mypwd

如果您使用 Anonymous/Forms 身份验证,请确保您已将 IIS 匿名身份验证配置为 运行 在应用程序池身份下,而不是默认的 IUSR。

这里有一个 ASP 页面用于测试:

<!DOCTYPE html>
<html>
<body>

<p>Output :</p>

<%

Set objNetwork = CreateObject("Wscript.Network")
Response.write("The current user is " & objNetwork.UserName)

cnn = "Provider=MSDASQL;Extended Properties=""Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=testdb;Trusted_Connection=yes;ColumnEncryption=Enabled;"" "
Set oDB = CreateObject( "ADODB.Connection" )
oDB.Open cnn
set oCmd = CreateObject("ADODB.Command") 
oCmd.ActiveConnection = cnn
oCmd.CommandText = "SELECT top 10 ID, Enc FROM tbl1"
set rst = oCmd.Execute()
rst.MoveFirst()
Response.write(cstr(rst("Enc")) )

%>

</body>
</html>