SQL 服务器 2017 上的 CLR 严格安全性

CLR Strict Security on SQL Server 2017

MSDN 在 this article 上说:

CLR uses Code Access Security (CAS) in the .NET Framework, which is no longer supported as a security boundary. A CLR assembly created with PERMISSION_SET = SAFE may be able to access external system resources, call unmanaged code, and acquire sysadmin privileges. Beginning with SQL Server 2017, an sp_configure option called clr strict security is introduced to enhance the security of CLR assemblies. clr strict security is enabled by default, and treats SAFE and EXTERNAL_ACCESS assemblies as if they were marked UNSAFE. The clr strict security option can be disabled for backward compatibility, but this is not recommended. Microsoft recommends that all assemblies be signed by a certificate or asymmetric key with a corresponding login that has been granted UNSAFE ASSEMBLY permission in the master database.

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

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

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

How can a CLR assembly created with PERMISSION_SET = SAFE may be able to access external system resources, call unmanaged code, and acquire sysadmin privileges?

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

Code Access Security Basics 的 MSDN 文档指出:

The .NET Framework provides a mechanism for the enforcement of varying levels of trust on different code running in the same application called Code Access Security (CAS). Code Access Security in .NET Framework should not be used as a mechanism for enforcing security boundaries based on code origination or other identity aspects. We are updating our guidance to reflect that Code Access Security and Security-Transparent Code will not be supported as a security boundary with partially trusted code, especially code of unknown origin. We advise against loading and executing code of unknown origins without putting alternative security measures in place.

然后指向 Security Changes in the .NET Framework 的页面,其中指出:

The most important change to security in the .NET Framework 4.5 is in strong naming.

然后指向 Enhanced Strong Naming 的文档,其中指出:

Strong name keys consist of a signature key and an identity key. The assembly is signed with the signature key and is identified by the identity key. Prior to the .NET Framework 4.5, these two keys were identical. Starting with the .NET Framework 4.5, the identity key remains the same as in earlier .NET Framework versions, but the signature key is enhanced with a stronger hash algorithm. In addition, the signature key is signed with the identity key to create a counter-signature.

此外,Secure Coding Guidelines 的文档指出:

Code Access Security and Security-Transparent Code will not be supported as a security boundary with partially trusted code. We advise against loading and executing code of unknown origins without putting alternative security measures in place...

因此,.NET 的安全模型在几年前发生了变化,但是 SQL Server(直到 SQL Server 2017)被允许继续使用旧的安全模型。似乎从 SQL Server 2017 开始,决定不再支持旧的安全模型。

我怀疑允许旧的安全模型是:

  • 防止SQL 服务器(至少是与 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):

作为最后度假村,可以考虑以下做法:

  1. 临时[master] 数据库设置为 TRUSTWORTHY ON

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

    EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [{DB_Owner_Login}];');
    
  2. [master]
  3. 中创建程序集
  4. 从程序集创建非对称密钥
  5. 放下程序集
  6. [master] 数据库设置为 TRUSTWORTHY OFF
  7. 从非对称密钥创建登录
  8. 授予该登录名 UNSAFE ASSEMBLY(这取代了将加载程序集的数据库设置为其所有者的 TRUSTWORTHY ON 登录获得UNSAFE ASSEMBLY权限)。

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

前几天我遇到了这个问题,它似乎并没有听起来那么糟糕(除了你不能再只创建一个 SAFE 程序集,而是需要对其进行签名等等,或者使用值得信赖)。

在我的测试中:

  • 我创建了一个程序集,它有一个 "SAFE" 方法和一个 "UNSAFE" (它使用了任务)。
  • 我将程序集创建为 SAFE(在构建并签名之后 等等)
  • 我围绕我的两个方法创建了 T-SQL 包装函数。
  • 当执行 "SAFE" 函数时一切正常。
  • 执行 "UNSAFE" 时,我收到 HostProtectionException。

对我来说,这表明对正在执行的内容仍有一些控制。我跟进了:

  • 使用 PERMISSION_SET = UNSAFE
  • 重新创建程序集
  • 重新创建函数
  • 现在,当我执行 UNSAFE 函数时,一切都按预期工作了。

所以我不太确定“clr strict security”文档中的声明是否 100% 正确。

我写了一篇博客-post 我的经历,如果你想自己测试,你可以在这里找到它:http://www.nielsberglund.com/2017/07/02/sql-server-2017-sqlclr-and-permissions/

尼尔斯

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

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

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