Locking down CLR

Locking down CLR

I recently ran into SQL 2017’s new CLR Strict Security. I was working with a client where we were optimizing some queries. One of the queries had a dynamically coded IN clause. In this case, I like to use a string splitting routine to split the IN clause into different values, and to put them into a temporary table to later join to. My string splitter of choice is here. This is one of the most efficient string splitters that I have run into, but it has one limitation: it won’t handle MAX data types. And at this client, the strings being created in the IN clause would exceed 8000 characters, requiring a MAX data type.

In this circumstance, I reverted to using a CLR string splitter. In the same article, you can download all the sample code, including a very efficient CLR string splitter. The direct link is here.

When we were installing this CLR string splitter on SQL Server 2017, we ran into a problem. SQL 2017 has beefed up the CLR security. This was preventing us from being able to install the CLR assembly.

SQL 2017 CLR Strict Security

Why did Microsoft make these changes? These changes make CLR, and thus SQL Server, more secure. In their “CLR strict security” article, they explain why:

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 (14.x), 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. SQL Server administrators can also add assemblies to a list of assemblies, which the Database Engine should trust. For more information, see sys.sp_add_trusted_assembly.

The article goes on to explain the permissions needed to create a CLR assembly starting in SQL 2017:

The following permissions required to create a CLR assembly when CLR strict security is enabled:

  • The user must have the CREATE ASSEMBLY permission

  • And one of the following conditions must also be true:

    • The assembly is signed with a certificate or asymmetric key that has a corresponding login with the UNSAFE ASSEMBLY permission on the server. Signing the assembly is recommended.

    • The database has the TRUSTWORTHY property set to ON, and the database is owned by a login that has the UNSAFE ASSEMBLY permission on the server. This option is not recommended.

Now, creating a signed certificate might be easy enough to do. But there are a lot of steps in actually doing this. You can read all about this here.

Is there another way?

That’s a lot of steps to go through just to create an assembly on your SQL Server instance. Let’s not even start thinking about having dozens of assemblies. Thankfully, Microsoft provided another way to do this within the CLR strict security framework. You can mark an assembly as trusted, using the sys.sp_add_trusted_assembly system stored procedure. This procedure adds the assembly to the trusted assemblies in sys.trusted_assemblies. This procedure has one required and one optional parameter. The required parameter is the SHA2_512 hash value of the assembly to add to the list of trusted assemblies for the server. The optional parameter is a user-defined description of the assembly.

Perhaps the easiest way to get the hash value is to install this assembly on a lower version of SQL Server, then script it out. Once we have that, we can use the HASHBYTES function to create the SHA2_512 hash value. Now that we have everything that we need, we can go ahead and call sys.sp_add_trusted_assembly. The following code performs all the needed actions, using the CLR splitter from the above article:

Now, you can go ahead and create the assembly, add the necessary functions, and start using it.


A couple of reference links that I came across while figuring all of this out: