TSQL CREATE ASSEMBLY FROM varbinary打破了class_name参数

问题描述 投票:1回答:1

我已将我的内部部署SQL Server 2008 R2数据库迁移到Azure SQL Server托管实例(SQL Server 2017)。一个数据库是一个存档(只读)数据库,一个是OLTP数据库,第三个是实用程序数据库,我保留了泛型函数,存储过程和维护脚本。除了实用程序DB中的CLR程序集外,所有三个DB的一切都非常顺利。程序集在TSQL代码中提供了Regex功能 - 非常有用!我的基础是Phil因子代码here。最初它是从已编译的DLL加载到内部部署的数据库中。它就像一个冠军。但是在SQL MI上,运行使用其中一个CLR函数的SP时出现以下错误。

Msg 10314,Level 16,State 11,Procedure dbo.globalSearch,Line 22 [Batch Start line 2] 尝试加载程序集ID为65541时,Microsoft .NET Framework中发生错误。服务器可能资源不足,或者程序集可能不受信任。再次运行查询,或检查文档以了解如何解决程序集信任问题。有关此错误的更多信息: System.IO.FileLoadException:无法加载文件或程序集'regexsqlclr,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'或其依赖项之一。发生了与安全性有关的错误。 (HRESULT异常:0x8013150A) System.IO.FileLoadException: at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName,String codeBase,Evidence assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark&stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks) 在System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef,Evidence assemblySecurity,RuntimeAssembly reqAssembly,StackCrawlMark&stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks) 在System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString,Evidence assemblySecurity,StackCrawlMark&stackMark,IntPtr pPrivHostBinder,Boolean forIntrospection) 在System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString,Evidence assemblySecurity,StackCrawlMark&stackMark,Boolean forIntrospection) 在System.Reflection.Assembly.Load(String assemblyString)

我已经尝试使用this MSDN帖子中的步骤解决程序集信任问题,具体执行

sys.sp_add_trusted_assembly

哪个成功,但什么都没改变。然后我认为,因为它建议它无法从文件加载,这似乎有意义,因为在我无法访问文件系统的SQL MI中不存在该文件,我应该尝试从varbinary删除并重新创建。我只是说它似乎有意义,因为除了我最初加载它之外的任何其他内部部署服务器上也不存在该文件,并且它在所有这些服务器上都能完美运行。但是,我愿意尝试任何事情!因此,使用SSMS,我将程序集编写为DROPCREATE,它使用FROM BINARY语法,同样编写了所有函数。 CREATE ASSEMBLY成功了,所以我在想我是在正确的轨道上。然后我尝试创建第一个函数和BAM,另一个错误!这次错误读取

消息6505,级别16,状态2,过程RegexIndex,第2行 在程序集“RegexFunctions”中找不到Type'RegexSQLCLR.RegularExpressionFunctions'。

我一直在谷歌搜索几个小时试图找到解决这个问题的方法,并且没有运气。即使EXTERNAL NAME子句的类部分的语法适用于从文件加载的程序集。我确认SSMS脚本编写的varbinary与原始DLL的二进制文件相同。微软论坛上有人建议我确保使用Any CPU选项编译DLL - 它确实如此。作为一个完整性检查,我在其中一个内部服务器上执行了相同的过程,即DROPCREATE ASSEMBLY FROM BINARY,并得到了完全相同的结果:我无法加载任何CLR函数!我已经尝试过所有可以想到的类名称,我能想到的,但无济于事。这是CREATE ASSEMBLYCREATE FUNCTION的代码

CREATE ASSEMBLY [RegexFunction]
AUTHORIZATION [dbo]
FROM 0x4D5A90000 *truncated_for_brevity*
WITH PERMISSION_SET = SAFE

CREATE FUNCTION RegExIndex
   (
    @Pattern NVARCHAR(4000),
    @Input NVARCHAR(MAX),
    @Options int
   )
RETURNS int
AS EXTERNAL NAME 
   RegexFunction.[RegexSQLCLR.RegularExpressionFunctions].RegExIndex
GO

RegexSQLCLR是原始DLL的名称,RegularExpressionFunctions是该类的名称。 RegexSQLCLR也是使用name后在sys.assembly_filesCREATE ASSEMBLY FROM BINARY专栏中指定的名称;原始DLL的完整路径是在name列中。

.net sql-server .net-assembly sqlclr azure-sql-managed-instance
1个回答
0
投票

所以,这里有一系列问题:

  1. 第一个问题是,由于潜在(但可能未经证实)安全问题,未签名的程序集(或者甚至没有已经授予UNSAFE ASSEMBLY权限的基于签名的匹配登录的已签名程序集)不再被视为“安全”。因此,从SQL Server 2017开始,引入了一个名为“CLR strict security”的新服务器级配置设置,并强制所有程序集满足标记为UNSAFE的程序集的要求。 PERMISSION_SETSAFEEXTERNAL_ACCESS选项仍然像以前一样工作,这只是加载程序集和从它们执行SQLCLR对象的问题。您遇到的问题是SAFE程序集永远不需要签名(尽管它们可能已经存在,例如我的SQL# SQLCLR库中的所有程序集,并且签名它们也有好处,即使它们只包含SAFE代码也会保持为PERMISSION_SET = SAFE)所以大多数都没有签名,但现在他们需要。因此,在将数据库从2017年之前升级/迁移到SQL Server 2017或更高版本时,会引发安全性错误。 一种选择是简单地禁用“CLR严格安全性”,或者另一种选择是为程序集所在的DB启用TRUSTWORTHY。两者都是不太安全的选择。我不确定“CLR严格安全”被禁用的“不安全”(实际上,它可能是微软的一个巨大的过度反应),但很明显,首选是保持启用。启用TRUSTWORTHY绝对是一个非常糟糕的选择:PLEASE, Please, please Stop Using Impersonation, TRUSTWORTHY, and Cross-DB Ownership Chaining。 Microsoft为解决这种情况而发布的机制是“可信组件”功能。不幸的是,这个功能也是一个糟糕的选择:它绝不是必需的(好吧,只需要Azure SQL数据库,它不再支持SQLCLR,但“可信组件”代码已经编写)并且只有因为没有人知道现有的功能已经解决了这种情况,并以更好的方式。 Please see: SQLCLR vs. SQL Server 2017, Part 4: “Trusted Assemblies” - The Disappointment。该帖子详细介绍了“可信组件”的问题以及如何解决现有的无符号组件问题(即在DB中使用程序集创建证书,签署程序集,在master中创建相同的证书)仅限公钥,从master中的证书创建登录,最后授予该登录UNSAFE ASSEMBLY权限)。
  2. 我尝试使用成功的sys.sp_add_trusted_assembly来解决汇编信任问题,但没有改变。 我不确定您用于散列的值是多少,但该存储过程不会验证散列是否与任何内容匹配。它只是将哈希加载到内部表中,以便在引用程序集时从以后读取。然后它将查看程序集的哈希值是否与存储哈希的内部表中的值匹配。所以它应该几乎总是成功(只要你给它一个有效的二进制值,可能是一个SHA2_256哈希)。
  3. 我认为,因为它建议它无法从文件加载,这似乎有意义,因为SQL MI中不存在我无法访问文件系统的文件 这只是一种误解。您是正确的,Azure SQL数据库托管实例中没有文件系统访问权限,但在这种情况下,文件系统是存储通过CREATE ASSEMBLY加载的程序集的内部表。错误是说无法将程序集从表加载到内存中。这是由于上面第1项中提到的安全问题。因此删除和重新创建程序集实际上并没有做任何事情。
  4. Microsoft论坛上有人建议我确保使用Any CPU选项编译DLL 我不知道为什么会出现这种情况。同样,这里的任何代码都没有错。
  5. AS EXTERNAL NAME RegexFunction.[RegexSQLCLR.RegularExpressionFunctions].RegExIndex 不知道为什么RegexSQLCLR被放在那里,但格式是(没有名称空间): AssemblyName.ClassName.MethodName 或(带命名空间): AssemblyName.[NameSpaceName.ClassName].MethodName
  6. 再次,TRUSTWORTHY ON是一个bad choice, and entirely unnecessary
© www.soinside.com 2019 - 2024. All rights reserved.