Question :
My database is currently isolated in its own instance and VM. My customer is retiring that server and I need to migrate the DB to a new environment. My DB uses CLR, so the new environment needs to have that enabled.
The customer proposed using an existing server with an existing SQLServer 2014 Standard instance hosting DBs from other software vendors on it. I’m concerned about incurring a sort of “you break it, you bought it” liability, since I can’t vouch for the security strategy of those other DBs or their front-ends. I don’t want to do something that would introduce a significant risk.
I run into similar scenarios with other customers from time to time. I’m a database developer. I occasionally provide DBA services pertaining to my own product for my small to medium business customers, but I am by no means a skilled DBA. Each customer has different budgets, priorities, IT staff, and security policies, but generally none of them have IT/DBAs that can understand and/or make competent risk assessments at this level of detail.
How would enabling CLR on a shared instance affect the security of the other DBs? (I am not asking about database-level permission_set levels, just enabling CLR itself). I need to understand the risk (if there is any) well enough to be able to advise a ‘best practice’ and a customer-specific ‘secure enough’ alternative.
Answer :
Given that we are dealing with a shared instance, it should be safe to assume that none of the logins for the “customer” DBs has sysadmin
privileges or has been granted the CONTROL SERVER
permission.
Under such conditions, there should not be any security risk to having SQLCLR enabled, regardless of what many people seem to claim. Having the instance-level “CLR enabled” option enabled merely allows for a login that has the appropriate permission to load assemblies, and for loaded assemblies to be used by anyone granted access to the objects in those assemblies.
If users cannot load assemblies, then there can be no risk of having unknown code in assemblies, because there won’t be any assemblies. Then, if one user (such as yourself) is granted the CREATE ASSEMBLY
permission (which should be coupled with using Certificates to handle the assembly security), then only you can load assemblies.
Of course, for SQL Server 2005 – 2016, and for SQL Server 2017 and newer that has the “CLR strict security” instance-level configuration option disabled, the database owner (i.e. the dbo
user) and any user in the db_owner
fixed database role can create SAFE
assemblies, but those aren’t a security risk. Sure, they might be a performance risk, but the same is true for sloppy data modeling, T-SQL, triggers, etc. If the various vendors are not dbo
for their databases, then this is a non-issue. If the vendors are dbo
for their respective databases and the desire is to prevent them creating SAFE
assemblies, it is easy enough to create an instance-wide DDL trigger for the CREATE ASSEMBLY
statement and issue a ROLLBACK
if the user is not you and/or it is not executed within your database.
If someone is a member of the sysadmin
instance-level role, or granted the CONTROL SERVER
instance-level permission, then they can also load assemblies. BUT, and here is what most “security” related recommendations miss: having “CLR enabled” disabled does not protect against someone who is a sysadmin
or has CONTROL SERVER
permission because they have permission to enable the “CLR enabled” option (and enable xp_cmdshell
, etc and do whatever they want)!
There is no inherent risk in having this option enabled because having it enabled does not give anyone the permission to load assemblies that pose a security risk (in SQL Server 2005 – 2016, dbo
and users in db_owner
role can load SAFE
assemblies). And, once loaded, assemblies marked as EXTERNAL_ACCESS
or UNSAFE
need additional security (i.e. Certificates / strong naming, not TRUSTWORTHY
) in order for their code to be executed. And, starting in SQL Server 2017 all assemblies, by default, need that additional security just to be loaded in the first place. And, that additional security (for the operation of the assembly) requires sysadmin
level permissions:
- In the unfortunate case of someone setting the database to
TRUSTWORTHY ON
, the login that owns the DB needs to have either theEXTERNAL ACCESS ASSEMBLY
orUNSAFE ASSEMBLY
permission (for SQL Server 2017+ with “CLR strict security” enabled — the default — it must beUNSAFE ASSEMBLY
), which can only be granted by a sysadmin (these permissions are obviously implied if the owning login is asysadmin
). Hopefully vendor DBs would never haveTRUSTWORTHY
enabled. - When assemblies are signed, a certificate or asymmetric key needs to be created in the
[master]
DB, then a login needs to be created from that, then that login needs to be granted either theEXTERNAL ACCESS ASSEMBLY
orUNSAFE ASSEMBLY
permission (for SQL Server 2017+ with “CLR strict security” enabled — the default — it must beUNSAFE ASSEMBLY
).
For some examples of handling SQLCLR security, please see:
- Stairway to SQLCLR Level 3: Security (General and SAFE Assemblies)
- Stairway to SQLCLR Level 4: Security (EXTERNAL and UNSAFE Assemblies)
That being said, as David Browne noted in a comment on this answer:
Another important point is about the trust that presumably exists among the stakeholders for the various databases. In a corporate environment, everyone is expected to be trustworthy and cooperative. in a 3rd party hosting environment, you have to assume that the owner of the adjacent workload is a completely untrusted and even malicious actor. Lots of not-perfectly-safe things are safe-enough to do behind a firewall and among friends.