SQL Server 2017 上的 CLR 严格安全性

Posted

技术标签:

【中文标题】SQL Server 2017 上的 CLR 严格安全性【英文标题】:CLR Strict Security on SQL Server 2017 【发布时间】:2017-10-20 08:30:08 【问题描述】:

this article 上的 MSDN 说:

CLR 使用 .NET Framework 中的代码访问安全 (CAS),这不是 不再支持作为安全边界。使用创建的 CLR 程序集 PERMISSION_SET = SAFE 可能能够访问外部系统资源, 调用非托管代码,并获得系统管理员权限。以。。。开始 SQL Server 2017,一个名为 clr strict security 的 sp_configure 选项是 引入以增强 CLR 程序集的安全性。 clr 严格 默认情况下启用安全性,并处理 SAFE 和 EXTERNAL_ACCESS 组件,就好像它们被标记为不安全一样。 clr 严格安全 可以禁用选项以实现向后兼容性,但这不是 推荐的。 Microsoft 建议所有程序集都由 具有相应登录名的证书或非对称密钥 在 master 数据库中授予了 UNSAFE ASSEMBLY 权限。

使用PERMISSION_SET = SAFE 创建的 CLR 程序集如何能够访问外部系统资源、调用非托管代码并获得系统管理员权限?

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

据我了解,CLR 程序集不再是安全的,这非常不幸。

【问题讨论】:

【参考方案1】:

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

EXEC sp_configure 'show advanced options', 1
RECONFIGURE;
EXEC sp_configure 'clr strict security', 0;
RECONFIGURE;

对于想要继续工作的人来说,这是最简单的解决方案

【讨论】:

它工作得很好。亲爱的侯赛因,简短回答的坦克 那我怎么仍然得到:配置选项'clr strict security'不存在,或者它可能是一个高级选项。运行那个? @jenson-button-event 是的,你应该运行这个命令来让你在你的 sql server 实例上使用 clr 重点是这仅适用于 2017+ 数据库实例【参考方案2】:

使用 PERMISSION_SET = SAFE 创建的 CLR 程序集如何能够访问外部系统资源、调用非托管代码并获得系统管理员权限?

这是由于 .NET Framework 从 4.5 版开始的安全性更改(我相信)。

Code Access Security Basics 的 MSDN 文档状态:

.NET Framework 提供了一种机制,用于对运行在同一应用程序中的不同代码实施不同级别的信任,称为代码访问安全 (CAS)。 .NET Framework 中的代码访问安全性不应用作基于代码来源或其他身份方面实施安全边界的机制。我们正在更新我们的指南,以反映代码访问安全性和安全透明代码将不被支持作为部分受信任代码的安全边界,尤其是未知来源的代码。我们建议不要在未采取替代安全措施的情况下加载和执行来源不明的代码。

然后指向Security Changes in the .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 版本,以及

负责从 Azure SQL 数据库中突然删除 SQLCLR 作为受支持的功能(在 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...)创建证书,但这不适用于Visual Studio(依赖于MSBuild)/ SSDT,因为使用证书需要使用signtool,而MSBuild 使用sn .

为了使其可行,以便 Visual Studio / MSBuild / SSDT 发布过程正常工作(这反过来意味着任何人都可以创建一个能够创建非对称密钥的完全独立的 .sql 脚本不依赖外部文件),CREATE ASYMMETRIC KEY 命令需要增强以允许从二进制字符串创建。我在 Microsoft Connect 上提出了这个建议——Allow Asymmetric Key to be created from binary hex bytes string just like CREATE CERTIFICATE——所以请支持它:-)。

或者(目前,在 MS 希望创建更好的方法之前,例如我的非对称密钥建议),您可以尝试我在以下博客文章中描述的两种技术中的任何一种(都可以与 SSDT 完全配合):

SQLCLR vs. SQL Server 2017, Part 2: “CLR strict security” – Solution 1 SQLCLR vs. SQL Server 2017, Part 3: “CLR strict security” – Solution 2

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

    暂时[master]数据库设置为TRUSTWORTHY ON

    要成功执行下一步(即CREATE ASSEMBLY),作为数据库所有者的登录名(即[master][dbo]用户使用的相同SID)需要具有UNSAFE ASSEMBLY权限。如果[master]sa 或任何其他系统管理员所有,则它拥有所有权限并且已满足此要求。但是,如果[master] 由低权限登录拥有(“最佳实践”),那么当TRUSTWORTHYON 时,您将需要执行以下语句以使CREATE ASSEMBLY 工作:

    EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [DB_Owner_Login];');
    
    [master] 中创建程序集 从程序集创建非对称密钥 删除程序集 将[master] 数据库设置为TRUSTWORTHY OFF 从非对称密钥创建登录 将UNSAFE ASSEMBLY 授予该登录名(这取代了将加载程序集的数据库设置为TRUSTWORTHY ON 为其所有者登录拥有UNSAFE ASSEMBLY 权限的需要) .

请注意,我确实没有在此处将新的“受信任的程序集”功能作为选项包含在内。没有提到它的原因是它的缺陷多于好处,更不用说它完全没有必要,因为现有功能已经处理了“受信任的程序集”旨在解决的情况。有关这方面的完整详细信息以及处理现有未签名程序集的正确方法的演示,请参阅:SQLCLR vs. SQL Server 2017, Part 4: “Trusted Assemblies” – The Disappointment。

【讨论】:

【参考方案3】:

前几天我遇到了这个问题,它似乎并不像听起来那么糟糕(除了你不能再创建一个安全的程序集,而是需要对其进行签名等,或者使用 TRUSTWORTHY) .

在我的测试中:

我创建了一个具有“安全”方法和“不安全”方法的程序集 (它使用了任务)。 我将程序集创建为 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,感谢您的文章,非常棒。是否可以签署上传的程序集? IE。我的数据库中有一个程序集,我可以在那个地方签名吗?没有下载到dll,签名然后再次上传到数据库? 嗨@ZedZip,你使用的是什么版本的SQL——你可以使用白名单吗? 正确的问题。我需要将解决方案部署到2012-2019版本的SQL Server

以上是关于SQL Server 2017 上的 CLR 严格安全性的主要内容,如果未能解决你的问题,请参考以下文章

使用 SQL-CLR 函数在 SQL Server 中验证加密数据的安全性

复制 SQL Server CLR 函数

SQL Server 2008 CLR 聚合函数

SQL CLR 在 SQL Server 中随机失败

SQL Server 中的 CLR 程序集 C#

CLR SQL Server UDF 问题