使用 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 开始,似乎决定不再支持旧的安全模型。
我怀疑允许旧的安全模型是:
所以,是的,这有点糟糕。这意味着(至少目前)需要首先创建一个证书或非对称密钥(用于签署任何要加载的程序集)到[master],然后创建一个从该登录名登录,然后将UNSAFE ASSEMBLY 授予该登录名。这与加载 EXTERNAL_ACCESS 和 UNSAFE 程序集时需要执行的事件序列相同,但不幸的是,现在甚至需要为 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 完全配合):
作为最后的手段,您可以考虑以下方法:
-
暂时将[master]数据库设置为TRUSTWORTHY ON
要成功执行下一步(即CREATE ASSEMBLY),作为数据库所有者的登录名(即[master]的[dbo]用户使用的相同SID)需要具有UNSAFE ASSEMBLY权限。如果[master] 归sa 或任何其他系统管理员所有,则它拥有所有权限并且已满足此要求。但是,如果[master] 由低权限登录拥有(“最佳实践”),那么当TRUSTWORTHY 为ON 时,您将需要执行以下语句以使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。