使用 PERMISSION_SET = SAFE 创建的 CLR 程序集如何能够访问外部系统资源、调用非托管代码并获得系统管理员权限?
这是由于从 4.5 版(我相信)开始在 .NET Framework 中进行的安全更改。
代码访问安全基础知识的 MSDN 文档指出:
.NET Framework 提供了一种机制,用于对运行在同一应用程序中的不同代码实施不同级别的信任,称为代码访问安全 (CAS)。.NET Framework 中的代码访问安全性不应用作基于代码来源或其他身份方面强制实施安全边界的机制。我们正在更新我们的指南,以反映代码访问安全性和安全透明代码将不被支持作为部分受信任代码的安全边界,尤其是未知来源的代码。我们建议不要在未采取替代安全措施的情况下加载和执行来源不明的代码。
然后指向.NET Framework 中的安全更改页面,其中指出:
.NET Framework 4.5 中对安全性最重要的更改是强命名。
然后指向增强强命名的文档,其中指出:
强名称密钥由签名密钥和身份密钥组成。程序集使用签名密钥进行签名,并由身份密钥标识。在 .NET Framework 4.5 之前,这两个键是相同的。从 .NET Framework 4.5 开始,标识密钥与早期 .NET Framework 版本中的相同,但签名密钥通过更强大的哈希算法得到了增强。此外,签名密钥使用身份密钥进行签名以创建副签名。
此外,安全编码指南的文档指出:
不支持代码访问安全性和安全透明代码作为部分受信任代码的安全边界。我们建议不要在没有采取替代安全措施的情况下加载和执行来源不明的代码......
因此,.NET 的安全模型几年前发生了变化,但 SQL Server(直到 SQL Server 2017)已被允许继续使用旧的安全模型。从 SQL Server 2017 开始,似乎决定不再支持旧的安全模型。
我怀疑允许旧的安全模型是:
所以,是的,这有点糟糕。这意味着(至少目前)是需要首先创建一个证书或非对称密钥(已用于签署要加载的任何程序集)[master]
,然后创建一个登录名,然后授予UNSAFE ASSEMBLY
该登录名。EXTERNAL_ACCESS
这与加载和程序集时需要执行的事件序列相同UNSAFE
,但不幸的是,现在甚至需要为程序集完成SAFE
。
目前没有机制以完全可移植的方式(即不依赖外部文件)处理此问题,并且在没有手动干预的情况下无法由 Visual Studio / SSDT 处理。情况已经如此,但至少可以创建一个设置来以完全可移植的方式处理这个问题(即完全包含在 .sql 脚本中):请参阅SQLCLR 7 级的阶梯:开发和安全了解详细信息(这是我写的一篇文章)。
可以从十六进制字节FROM BINARY = 0x...
(signtool
即sn
.
为了使它可行,以便 Visual Studio / MSBuild / SSDT 发布过程正常工作(这反过来意味着任何人都可以创建一个完全独立的 .sql 脚本,该脚本能够创建非对称密钥而无需依赖外部文件),CREATE ASYMMETRIC KEY
需要增强该命令以允许从二进制字符串创建。我在 Microsoft Connect 上提出了这个建议——允许从二进制十六进制字节字符串创建非对称密钥,就像 CREATE CERTIFICATE 一样——所以请支持它:-)。
或者(目前,直到 MS 希望创建更好的方法,例如我的非对称密钥建议),您可以尝试我在以下博客文章中描述的两种技术中的任何一种(都可以与 SSDT 完全配合):
作为最后的手段,您可以考虑以下方法:
暂时将[master]
数据库设置为TRUSTWORTHY ON
为使下一步(即CREATE ASSEMBLY
)成功执行,作为数据库所有者的登录名(即与[dbo]
用户使用相同的 SID [master]
)需要具有UNSAFE ASSEMBLY
权限。如果[master]
由sa
或任何其他系统管理员拥有,则它具有所有权限并且已满足此要求。但是,如果[master]
由低权限登录拥有(“最佳实践”),那么您将需要执行以下语句才能在isCREATE ASSEMBLY
时工作:TRUSTWORTHY
ON
EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [{DB_Owner_Login}];');
- 在中创建装配体
[master]
- 从程序集中创建非对称密钥
- 删除程序集
- 将
[master]
数据库设置为TRUSTWORTHY OFF
- 从非对称密钥创建登录
- 授予
UNSAFE ASSEMBLY
该登录名(这取代了将加载程序集的数据库设置为TRUSTWORTHY ON
及其所有者登录名具有UNSAFE ASSEMBLY
权限的需要)。
请注意,我没有在此处包含新的“受信任的程序集”功能作为选项。没有提到它的原因是它的缺陷多于好处,更不用说它完全没有必要,因为现有功能已经处理了“受信任的程序集”旨在解决的情况。有关这方面的完整详细信息以及处理现有未签名程序集的正确方法的演示,请参阅:SQLCLR 与 SQL Server 2017,第 4 部分:“受信任的程序集” - 失望。