Sql server 如何从SQL Server中的所有对象中删除加密?
我有100多个加密的过程和函数要解密(我正在尝试bacpac文件导出,但由于过程被加密而失败)。我尝试对就地alter使用解密向导,但出现错误: 定义无效。找不到创建关键字 当我尝试查看存储过程的DDL脚本(使用dbforge sql decryptor)时,会出现以下错误: 无法显示对象dbo.pt_块的定义,因为它是由第三方工具加密的 我找不到解决这个问题的办法。是否有任何解决方案或其他工具可用于此 编辑:我找到了哪些提及 获取源代码并发出不带加密选项的ALTER命令。只需获取源代码并使用加密删除 我怎样才能做到这一点 编辑:我已启用远程DAC。我怎样才能解密一切?从这个被接受的答案有一个断开的链接Sql server 如何从SQL Server中的所有对象中删除加密?,sql-server,dbforge,Sql Server,Dbforge,我有100多个加密的过程和函数要解密(我正在尝试bacpac文件导出,但由于过程被加密而失败)。我尝试对就地alter使用解密向导,但出现错误: 定义无效。找不到创建关键字 当我尝试查看存储过程的DDL脚本(使用dbforge sql decryptor)时,会出现以下错误: 无法显示对象dbo.pt_块的定义,因为它是由第三方工具加密的 我找不到解决这个问题的办法。是否有任何解决方案或其他工具可用于此 编辑:我找到了哪些提及 获取源代码并发出不带加密选项的ALTER命令。只需获取源代码并使用加
编辑:通过卸载创建加密过程的第三方工具,问题已经得到解决。下面是一个PowerShell示例,它创建了一个包含所有加密对象的脚本文件,该脚本文件来自Paul White的文章。将2个连接字符串中的数据源和初始目录更改为所需的服务器和数据库以及脚本文件路径 用于从系统表中检索值,因此需要
sysadmin
服务器角色成员身份。如果远程运行,则必须启用SQL Server远程管理连接
选项,并允许TCP端口1434通过防火墙
自定义后,可以从PowerShell ISE或命令提示符运行脚本。示例命令行调用,假设脚本保存到文件“Decrypt Objects.ps1”
PowerShell脚本:
# PowerShell implementation of T-SQL code from https://sqlperformance.com/2016/05/sql-performance/the-internals-of-with-encryption
Function Get-DecryptedString($pwd, $data) {
$key = [System.Array]::CreateInstance([int], 256)
$box = [System.Array]::CreateInstance([int], 256)
$cipher = [System.Array]::CreateInstance([byte], $data.Length)
for ($i = 0; $i -lt 256; ++$i) {
$key[$i] = $pwd[$i % $pwd.Length]
$box[$i] = $i
}
for ($j = $i = 0; $i -lt 256; ++$i) {
$j = ($j + $box[$i] + $key[$i]) % 256
$tmp = $box[$i]
$box[$i] = $box[$j]
$box[$j] = $tmp
}
for ($a = $j = $i = 0; $i -lt $data.Length; ++$i) {
++$a
$a %= 256
$j += $box[$a]
$j %= 256
$tmp = $box[$a]
$box[$a] = $box[$j]
$box[$j] = $tmp
$k = $box[(($box[$a] + $box[$j]) % 256)]
$cipher[$i] = ($data[$i] -bxor $k)
}
$decryptedString = [System.Text.Encoding]::Unicode.GetString($cipher)
return $decryptedString
}
Function Get-ClearObjectText($connectionString, $objectName) {
$getRc4KeyQuery = @"
DECLARE
@objectid integer = OBJECT_ID(@ObjectName),
@family_guid binary(16),
@objid binary(4),
@subobjid binary(2);
-- Find the database family GUID
SELECT @family_guid = CONVERT(binary(16), DRS.family_guid)
FROM sys.database_recovery_status AS DRS
WHERE DRS.database_id = DB_ID();
-- Convert object ID to little-endian binary(4)
SET @objid = CONVERT(binary(4), REVERSE(CONVERT(binary(4), @objectid)));
SELECT
-- Read the encrypted value
@imageval = SOV.imageval,
-- Get the subobjid and convert to little-endian binary
@subobjid = CONVERT(binary(2), REVERSE(CONVERT(binary(2), SOV.subobjid)))
FROM sys.sysobjvalues AS SOV
WHERE
SOV.[objid] = @objectid
AND SOV.valclass = 1;
-- Compute the RC4 initialization key
SELECT @RC4key = HASHBYTES('SHA1', @family_guid + @objid + @subobjid);
"@
$connection = New-Object System.Data.SqlClient.SqlConnection($dacConnectionString)
$connection.Open()
$command = New-Object System.Data.SqlClient.SqlCommand($getRc4KeyQuery, $connection)
($command.Parameters.Add("@ObjectName", [System.Data.SqlDbType]::NVarChar, 261)).Value = $objectName
($command.Parameters.Add("@imageval", [System.Data.SqlDbType]::VarBinary, -1)).Direction = [System.Data.ParameterDirection]::Output
($command.Parameters.Add("@RC4key", [System.Data.SqlDbType]::Binary, 20)).Direction = [System.Data.ParameterDirection]::Output
[void]$command.ExecuteNonQuery()
$imageval = $command.Parameters["@imageval"].Value
$RC4key = $command.Parameters["@RC4key"].Value
$connection.Close()
$decryptedString = Get-DecryptedString -pwd $RC4key -data $imageval
Return $decryptedString
}
# ############
# ### MAIN ###
# ############
# DAC connection string for decryption
$dacConnectionString = "Data Source=admin:YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI"
# normal connection string for encrypted object list
$connectionString = "Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI"
# target file path for clear encrypted objects DDL
$scriptFilePath = "C:\Scripts\EncryptedObjects.sql"
[void](New-Item -Path "C:\Scripts\EncryptedObjects.sql" -ItemType file -Force) # create directory (if needed) and empty script file
$EncryptedObjectQuery = @"
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name) AS QualifiedObjectName
FROM sys.objects
WHERE OBJECTPROPERTY(object_id, 'IsEncrypted') = 1;
"@
try {
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
$command = New-Object System.Data.SqlClient.SqlCommand($EncryptedObjectQuery, $connection)
$connection.Open()
$reader = $command.ExecuteReader()
while ($reader.Read()) {
$createObjectScript = Get-ClearObjectText -connectionString $dacConnectionString -objectName $reader["QualifiedObjectName"]
$createObjectScript | Out-File -FilePath $scriptFilePath -Append
"GO" | Out-File -FilePath $scriptFilePath -Append
}
$connection.Close()
}
catch {
throw
}
您将发现许多其他工具和脚本可以通过internet搜索实现这一点。我也发现了。请注意,对象加密实际上只是模糊处理。如果在没有任何管理访问的情况下访问未加密的内容是微不足道的,那么该功能的用处甚至更小,可以说它已经是了。假设您是计算机上的管理员,您可以通过启用
xp\u cmdshell
并调用sqlcmd
,或者通过安排执行相同操作的作业(sqlcmd-S admin:(local)
)来打开DAC连接。非常笨重,尤其是因为您必须编写一个一次性完成所有任务的脚本,但这是一个选项。如果您可以控制机器的防火墙(即,您不仅是系统管理员,而且是Windows管理员,PowerShell远程处理是一个选项),您还可以启用DAC进行远程访问(sp\u配置“远程管理员连接”
),这稍微简单一点。没有DAC连接就没有解决方案。请注意,远程DAC连接是一个可配置的选项。感谢您指出,我已启用远程DAC并更新了问题。我是一个完全的初学者,因此我为我的无知道歉。据我所知,当我在SSMS中使用DAC连接时,我可以运行此code在新查询中。从代码中,我看到我应该将“YourServer”更改为我的服务器详细信息,将“tempdb”更改为数据库。您能解释一下我还需要更改什么吗?@TheloniusMonk,SSMS只能运行T-SQL脚本(从技术上讲,它可以从PS窗口运行PowerShell,但对于新手来说,这个故事太长了)。我在回答中添加了有关修改和执行脚本的更多信息。请注意,只允许一个DAC连接,因此如果您以前建立了DAC连接,我建议您关闭SSMS。我使用用户名和密码登录数据库。这是否意味着我还必须将“Integrated Security=SSPI”更改为“User ID=xxx;password=xxx”?我是想知道这个脚本中的DAC连接是如何建立的(我通过使用admin:prefix成功地使用Powershell测试了DAC连接)@TheloniusMonk,是的,如果您想改用SQL身份验证,您需要更改您提到的连接字符串,尽管我不确定如果Windows身份验证有效,您为什么要这样做。我运行了脚本,但认为没有发生任何事情。对象仍然是加密的。
# PowerShell implementation of T-SQL code from https://sqlperformance.com/2016/05/sql-performance/the-internals-of-with-encryption
Function Get-DecryptedString($pwd, $data) {
$key = [System.Array]::CreateInstance([int], 256)
$box = [System.Array]::CreateInstance([int], 256)
$cipher = [System.Array]::CreateInstance([byte], $data.Length)
for ($i = 0; $i -lt 256; ++$i) {
$key[$i] = $pwd[$i % $pwd.Length]
$box[$i] = $i
}
for ($j = $i = 0; $i -lt 256; ++$i) {
$j = ($j + $box[$i] + $key[$i]) % 256
$tmp = $box[$i]
$box[$i] = $box[$j]
$box[$j] = $tmp
}
for ($a = $j = $i = 0; $i -lt $data.Length; ++$i) {
++$a
$a %= 256
$j += $box[$a]
$j %= 256
$tmp = $box[$a]
$box[$a] = $box[$j]
$box[$j] = $tmp
$k = $box[(($box[$a] + $box[$j]) % 256)]
$cipher[$i] = ($data[$i] -bxor $k)
}
$decryptedString = [System.Text.Encoding]::Unicode.GetString($cipher)
return $decryptedString
}
Function Get-ClearObjectText($connectionString, $objectName) {
$getRc4KeyQuery = @"
DECLARE
@objectid integer = OBJECT_ID(@ObjectName),
@family_guid binary(16),
@objid binary(4),
@subobjid binary(2);
-- Find the database family GUID
SELECT @family_guid = CONVERT(binary(16), DRS.family_guid)
FROM sys.database_recovery_status AS DRS
WHERE DRS.database_id = DB_ID();
-- Convert object ID to little-endian binary(4)
SET @objid = CONVERT(binary(4), REVERSE(CONVERT(binary(4), @objectid)));
SELECT
-- Read the encrypted value
@imageval = SOV.imageval,
-- Get the subobjid and convert to little-endian binary
@subobjid = CONVERT(binary(2), REVERSE(CONVERT(binary(2), SOV.subobjid)))
FROM sys.sysobjvalues AS SOV
WHERE
SOV.[objid] = @objectid
AND SOV.valclass = 1;
-- Compute the RC4 initialization key
SELECT @RC4key = HASHBYTES('SHA1', @family_guid + @objid + @subobjid);
"@
$connection = New-Object System.Data.SqlClient.SqlConnection($dacConnectionString)
$connection.Open()
$command = New-Object System.Data.SqlClient.SqlCommand($getRc4KeyQuery, $connection)
($command.Parameters.Add("@ObjectName", [System.Data.SqlDbType]::NVarChar, 261)).Value = $objectName
($command.Parameters.Add("@imageval", [System.Data.SqlDbType]::VarBinary, -1)).Direction = [System.Data.ParameterDirection]::Output
($command.Parameters.Add("@RC4key", [System.Data.SqlDbType]::Binary, 20)).Direction = [System.Data.ParameterDirection]::Output
[void]$command.ExecuteNonQuery()
$imageval = $command.Parameters["@imageval"].Value
$RC4key = $command.Parameters["@RC4key"].Value
$connection.Close()
$decryptedString = Get-DecryptedString -pwd $RC4key -data $imageval
Return $decryptedString
}
# ############
# ### MAIN ###
# ############
# DAC connection string for decryption
$dacConnectionString = "Data Source=admin:YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI"
# normal connection string for encrypted object list
$connectionString = "Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI"
# target file path for clear encrypted objects DDL
$scriptFilePath = "C:\Scripts\EncryptedObjects.sql"
[void](New-Item -Path "C:\Scripts\EncryptedObjects.sql" -ItemType file -Force) # create directory (if needed) and empty script file
$EncryptedObjectQuery = @"
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name) AS QualifiedObjectName
FROM sys.objects
WHERE OBJECTPROPERTY(object_id, 'IsEncrypted') = 1;
"@
try {
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
$command = New-Object System.Data.SqlClient.SqlCommand($EncryptedObjectQuery, $connection)
$connection.Open()
$reader = $command.ExecuteReader()
while ($reader.Read()) {
$createObjectScript = Get-ClearObjectText -connectionString $dacConnectionString -objectName $reader["QualifiedObjectName"]
$createObjectScript | Out-File -FilePath $scriptFilePath -Append
"GO" | Out-File -FilePath $scriptFilePath -Append
}
$connection.Close()
}
catch {
throw
}