如何从经典 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>
我维护着一个经典的 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>