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:

Related

Hi Wayne. Please don’t use the “Trusted Assemblies” feature. It is an entirely inferior and unnecessary “feature” that only exists because Microsoft needed something to provide some level of security for the few remaining assemblies that were allowed to exist once they pulled SQLCLR support from Azure SQL Database back in April of 2016. And it only exists in non-Azure SQL Server because existing DBs with unsigned assemblies that were either upgraded to 2017 or restored into 2017 were getting the “not trusted” error, and nobody at Microsoft knew that assemblies that were already loaded into SQL Server could be signed without needing to export, sign, and re-import. It was merely a knowledge oversight, and they had the “trusted assemblies” code that had been added for Azure so they un-hid it. It is something that never should have existed, and does a poor job of solving a problem that was solved back in SQL Server 2005. I cover all of this here:

Creating a certificate is really not that hard, and shouldn’t be discouraged since it is the optimal method of providing security for assemblies. And this hasn’t changed since SQLCLR was introduced in SQL Server 2005. In fact, Part 4 of my “SQLCLR vs SQL Server 2017” series is about signing existing unsigned assemblies, and it has example code showing how to do it.

Also, with regards to splitting strings:

a) this is built into SQL Server 2016 and newer via STRING_SPLIT, but that doesn’t return a Row / Element ID, so that is not usable for some folks / scenarios,

b) the SQLCLR library that I created, SQL# ( https://SQLsharp.com/ ), comes with a few string splitters. Starting in version 4.0, I added String_SplitInts which is for splitting a list of BIGINT / INT / SMALLINT / TINYINT values. It does the conversion to BIGINT in the .NET code so you get a result set of BIGINT back instead of strings. This is very fast for both CPU and elapsed times. It even includes an option for returning a single row of NULL if the input is NULL (some folks seem to like that). And when the input is known to never be over 4k characters, the “4k” version is even faster. I am mentioning SQL# because this is in the Free version, and the security is handled properly (using signatures) so no extra effort needs to be done to get it installed. It just works :).

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.