升级到 SQL Server 2017 后出现错误消息 10314,级别 16,状态 11,带有 SAFE 程序集

Sol*_*zky 2 sql-server errors sql-clr sql-server-2017

我有一个 SQL Server 2017 之前的数据库,我恢复到/升级到 SQL Server 2017。在这个数据库中,我有一个 SQLCLR 程序集。程序集被标记为SAFE因为它不执行任何需要更高级别权限的操作,并且数据库已TRUSTWORTHY禁用 / OFF。SQLCLR 函数和存储过程在迁移到 SQL Server 2017 之前按预期工作,但现在当我尝试执行其中任何一个时,我收到以下错误:

消息 10314,级别 16,状态 11,服务器 XXXXXXXXXXX,行 YYYYYY
      在 Microsoft .NET Framework 中尝试加载程序集 ID ZZZZZ 时出错。服务器可能会耗尽资源,或者程序集可能不受信任。再次运行查询,或检查文档以了解如何解决程序集信任问题。有关此错误的更多信息:
      System.IO.FileLoadException:无法加载文件或程序集“{assembly_name}”,版本=0.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一。发生与安全相关的错误。(来自 HRESULT 的异常:0x8013150A)

我已确认已在服务器/实例上启用 CLR 集成/SQLCLR。

Sol*_*zky 5

该错误是由clr strict securitySQL Server 2017 中新的服务器级配置选项造成的。这个新的安全设置禁止任何程序集,即使是那些标记为 的程序集,也不允许SAFE创建或加载到内存中以供执行,除非:

  • TRUSTWORTHYis的 Database 属性ON(不要这样做,因为这是一个不必要的安全风险)并且作为数据库所有者的 Login(即[dbo]用户使用的相同 SID )需要具有UNSAFE ASSEMBLY权限(如果所有者可能已经拥有该权限)是sa sysadmin固定服务器角色的成员,或者可能具有CONTROL SERVER权限)。
  • 的服务器级配置选项clr strict security被禁用/ 0(不要这样做,因为这是一个不必要的安全风险)
  • 程序集已签名,并且您有一个相应的基于签名的登录名已被授予UNSAFE ASSEMBLY权限(执行此操作)
  • 程序集的 SHA-512 哈希被注册为“可信程序集”(绝对要这样做,因为它有很多问题,更不用说一开始就不需要它)

为了解决这种情况,您需要做的只是以下步骤(这些步骤并不困难提供最高级别的安全性):

  1. 在程序集所在的数据库中创建证书
  2. 将证书(公钥和私钥)备份到文件(可选)
  3. 用证书签署程序集(或程序集)
  4. 删除私钥(以后可以从备份文件中恢复)(可选)
  5. 对于每个未签名的附加数据库,程序集SAFE
    1. 要么跳过这个子步骤(即跳到步骤 6),完成这些步骤,然后重复整个过程(这将导致每个数据库需要一个证书),或者
    2. 执行以下操作(这将导致总共一个证书,将用于所有数据库):
      1. 从备份文件(包括私钥!)创建相同的证书
      2. 用证书签署程序集(或程序集)
      3. 删除私钥(以后可以从备份文件中恢复)
  6. 将证书复制到[master](仅限公钥!)
  7. 从证书创建登录
  8. 授予基于证书的登录UNSAFE ASSEMBLY权限

一个简单的例子(减去可选的备份和私钥删除)是:

USE [{database_containing_unsigned_safe_assembly}];

CREATE CERTIFICATE [{certificate_name}]
  ENCRYPTION BY PASSWORD = '{some password}'
  WITH SUBJECT = '{simple description}',
  EXPIRY_DATE = '2099-12-31';

ADD SIGNATURE
  TO Assembly::[{assembly_name}]
  BY CERTIFICATE [{certificate_name}]
  WITH PASSWORD = '{some password}';

DECLARE @PublicKey VARBINARY(MAX),
        @SQL NVARCHAR(MAX);

SET @PublicKey = CERTENCODED(CERT_ID(N'{certificate_name}'));

SET @SQL = N'
CREATE CERTIFICATE [{certificate_name}]
  FROM BINARY = ' + CONVERT(NVARCHAR(MAX), @PublicKey, 1) + N';';
PRINT @SQL; -- DEBUG

EXEC [master].[sys].[sp_executesql] @SQL;

EXEC [master].[sys].[sp_executesql] N'
CREATE LOGIN [{login_name}]
  FROM CERTIFICATE [{certificate_name}];

GRANT UNSAFE ASSEMBLY TO [{login_name}]; -- REQUIRED!!!!
';
Run Code Online (Sandbox Code Playgroud)

可以在 PasteBin: Avoiding“Trusted Assemblies” - Demo上找到一个完整的示例(减去备份和私钥删除)

为什么你一个详细的解释应该使用证书,以及为什么你应该使用“可信大会”,来解决这个问题,在我的博客文章提供:
SQLCLR与SQL服务器2017年,第4部分:“受信任的组件” -失望

此外,鉴于围绕它的众多问题(包括安全问题),以及总体上缺乏使用它的好处,请考虑支持我让 Microsoft 删除新的“可信程序集”功能的请求:

受信任的程序集比证书问题更多,但功能更少 - 请删除