SQL Server 2017中的CLR严格安全性

23

这篇文章中MSDN表示:

CLR在.NET Framework中使用的代码访问安全(CAS)不再作为安全边界支持。使用PERMISSION_SET = SAFE创建的CLR程序集可能能够访问外部系统资源,调用非托管代码以及获取sysadmin权限。从SQL Server 2017开始,引入了一个名为clr strict security的sp_configure选项来增强CLR程序集的安全性。clr strict security默认启用,并将SAFE和EXTERNAL_ACCESS程序集视为标记为UNSAFE。可以为向后兼容禁用clr strict security选项,但不建议这样做。Microsoft建议所有程序集都使用证书或非对称密钥进行签名,并授予相应登录名在主数据库中的UNSAFE ASSEMBLY权限。

如何使用PERMISSION_SET = SAFE创建的CLR程序集可能能够访问外部系统资源,调用非托管代码以及获取sysadmin权限?

为什么CAS不再作为安全边界支持?

据我所知,CLR程序集现在不能再是安全的,这非常不幸。


在Visual Studio 2022中是否有更新的解决方案?我正在尝试将CLR发布到SQL Server 2019。在发布时出现以下错误:
使用SAFE或EXTERNAL_ACCESS选项为程序集'<assembly name>'创建或更改程序集失败,因为sp_configure的'clr strict security'选项设置为1。Microsoft建议您使用具有相应登录名的证书或非对称密钥签署程序集以获得UNSAFE ASSEMBLY权限。或者,您可以使用sp_add_trusted_assembly信任程序集。
- Aamir
@Aamir 尝试使用 ALTER DATABASE YourDatabase SET TRUSTWORTHY ON - Jesús López
3个回答

27

我知道这不是一个真正的解决方案,但你可以更改安全模式:

EXEC sp_configure 'show advanced options', 1
RECONFIGURE;
EXEC sp_configure 'clr strict security', 0;
RECONFIGURE;
这是那些想要继续他们工作的人最容易的解决方案。

它的工作非常好。谢谢你简明扼要的回答,亲爱的Hossein。 - Amirhossein
那我该怎么办才能继续运行并得到结果:“配置选项'clr strict security'不存在,或者它可能是一个高级选项。”? - jenson-button-event
@jenson-button-event 是的,您应该运行此命令,以便在 SQL Server 实例上使用 clr。 - hossein andarkhora
重要的是,这只适用于2017年及以后的数据库实例。 - jenson-button-event

25
一个以PERMISSION_SET = SAFE方式创建的CLR程序集,如何能够访问外部系统资源、调用非托管代码和获取sysadmin权限?这是因为.NET Framework在4.5版本(我想)开始进行了安全性方面的改变。 Code Access Security Basics的MSDN文档说道:
.NET Framework提供了一种机制,可以对同一应用程序中的不同代码强制执行不同级别的信任,称为代码访问安全性(CAS)。在.NET Framework中,不应将代码访问安全性用作基于代码来源或其他身份方面的强制实施安全边界的机制。我们正在更新我们的指导方针,以反映出针对未知源代码的部分可信代码,代码访问安全性和安全透明代码将不被支持作为安全边界。我们建议在没有采取备选安全措施的情况下,不要加载和执行未知来源的代码。
然后,文档指向.NET Framework中的安全性更改页面。
".NET Framework 4.5中最重要的安全变化在于强名称。文档Enhanced Strong Naming指出:强名称密钥由签名密钥和标识密钥组成。程序集使用签名密钥进行签名,并由标识密钥标识。在.NET Framework 4.5之前,这两个密钥是相同的。从.NET Framework 4.5开始,标识密钥与早期.NET Framework版本相同,但签名密钥使用更强的哈希算法进行增强。此外,签名密钥使用标识密钥进行签名以创建反向签名。另外,文档Secure Coding Guidelines指出:不支持代码访问安全性和安全透明代码作为部分受信任代码的安全边界。我们建议不要加载和执行未知来源的代码,除非实施了替代安全措施..."
因此,.NET 的安全模型已经改变多年,但 SQL Server(直到 SQL Server 2017)一直被允许继续使用旧的安全模型。似乎从 SQL Server 2017 开始,决定不再支持旧的安全模型。
我怀疑允许使用旧的安全模型是为了:
- 防止 SQL Server(至少是 CLR 相关的功能/组件)基于更新的 .NET Framework 版本,并且 - 导致 SQLCLR 作为 Azure SQL Database 支持的功能突然被移除(支持在 2014 年底推出 v12 时已添加,但在 2016 年 4 月 15 日完全删除)。

所以,是的,这有点糟糕。至少现在意味着需要首先创建一个证书或非对称密钥(已用于签名任何要加载的程序集)到[master],然后创建一个登录用户,并授予该登录用户UNSAFE ASSEMBLY权限。这与加载EXTERNAL_ACCESSUNSAFE程序集所需的事件序列相同,但现在,不幸的是,即使是SAFE程序集也需要这样做。

目前没有机制可以以完全可移植的方式处理此问题(即不依赖于外部文件),也无法通过Visual Studio / SSDT进行处理而不需要手动干预。这种情况已经存在了一段时间,但至少可以创建一个设置来以完全可移植的方式处理此问题(即完全包含在.sql脚本中):请参见Stairway to SQLCLR Level 7: Development and Security获取详细信息(这是我撰写的一篇文章)。

可以从十六进制字节(即FROM BINARY = 0x...)创建证书,但在使用证书时需要使用signtool,而MSBuild使用sn。这在Visual Studio(依赖于MSBuild)/ SSDT中无法实现。
为了使Visual Studio / MSBuild / SSDT发布过程可行(这反过来意味着任何人都能够创建完全自包含的.sql脚本,能够创建非对称密钥而不依赖外部文件),CREATE ASYMMETRIC KEY命令需要增强以允许从二进制字符串创建。我已经在Microsoft Connect上提出了这个建议-允许像CREATE CERTIFICATE一样从二进制十六进制字节字符串创建非对称密钥-请支持它:-)。
或者(暂时),您可以尝试我在以下博客文章中描述的两种技术之一(两者都与SSDT完全兼容)。

作为最后的手段,您可以考虑以下方法:

  1. TEMPORARILY set the [master] Database to TRUSTWORTHY ON

    For the next step (i.e. CREATE ASSEMBLY) to execute successfully, the Login that is the database owner (i.e. same SID used by the [dbo] User of [master]) needs to have the UNSAFE ASSEMBLY permission. If [master] is owned by sa or any other sysadmin, then it has all permissions and this requirement has been satisfied. But, if [master] is owned by a low-privileged login (a "best practice"), then you will need to execute the following statement in order for the CREATE ASSEMBLY to work when TRUSTWORTHY is ON:

    EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [{DB_Owner_Login}];');
    
  2. Create the Assembly in [master]
  3. Create the Asymmetric Key from the Assembly
  4. Drop the Assembly
  5. set the [master] Database to TRUSTWORTHY OFF
  6. Create the Login from the Asymmetric Key
  7. Grant UNSAFE ASSEMBLY to that Login (this replaces the need for the DB where the Assembly is loaded to be set to TRUSTWORTHY ON and for its owner Login to have the UNSAFE ASSEMBLY permission).
请注意,我在这里没有将新的“可信程序集”功能作为选项包含。原因是它有比好处更多的缺陷,更不用说它在第一次使用时完全是不必要的,因为现有功能已经处理了“可信程序集”所要解决的情况。有关详细信息和演示如何处理现有的未签名程序集,请参见:SQLCLR vs. SQL Server 2017, Part 4: “Trusted Assemblies” – The Disappointment

2
前几天我偶然发现了这个问题,它似乎并不像听上去的那样糟糕(除了你不能再只创建一个"SAFE"程序集,而是需要对其进行签名等操作,或者使用 TRUSTWORTHY)。
在我的测试中:
- 我创建了一个程序集,其中包含一个"SAFE"方法和一个"UNSAFE"方法(它使用了Task)。 - 我将程序集创建为"SAFE"(在构建并签名后等操作之后)。 - 我在我的两个方法周围创建了 T-SQL 包装函数。 - 当执行"SAFE"函数时,一切正常。 - 当执行"UNSAFE"函数时,我收到了一个HostProtectionException异常。
对我来说,这表明仍然有一些控制正在执行。我接着做了以下工作:
- 使用 PERMISSION_SET = UNSAFE 重新创建了程序集。 - 重新创建了函数。 - 现在当我执行 UNSAFE 函数时,所有的事情都按预期进行。
因此,我并不确定文档中关于'clr strict security'的陈述是否100%正确。
我写了一篇关于我的经验的博客文章,如果你想自己尝试一下,可以在这里找到链接:http://www.nielsberglund.com/2017/07/02/sql-server-2017-sqlclr-and-permissions/ Niels

非常好的博客文章,非常感谢。所以你认为句子“可能能够访问外部系统资源、调用非托管代码并获取 sysadmin 权限”是不正确的。也许你需要做一些花哨和奇怪的事情来绕过安全检查。 - Jesús López
嗨,耶稣!是的 - 我认为这不正确,至少根据我的测试结果。 - Niels Berglund
嗨Niels,感谢您的文章,非常棒。是否可以对上传的程序集进行签名?也就是说,我在数据库中有一个程序集,我可以在原地对其进行签名吗?而不需要将其下载为dll,签名,然后再次上传到数据库中? - ZedZip
嗨@ZedZip,你使用的SQL版本是什么?你能使用白名单吗? - Niels Berglund
正确的问题。我需要将解决方案部署到 SQL Server 2012-2019 版本。 - ZedZip
@ZedZip 关于“是否可以对上传的程序集进行签名?”是的,这很容易实现,我在我的文章中展示了一个例子:“SQLCLR vs. SQL Server 2017, Part 4: “Trusted Assemblies” – The Disappointment (Msg 10314)”。程序集是间接签名的,因此 DLL 实际上并没有被更改。但是,这正是微软从未需要将“受信任的程序集”功能添加到独立产品中的原因(仅在 Azure SQL DB 中需要,在那里您没有 master 数据库)。 - Solomon Rutzky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接