打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
解决因SQL Server数据库引用程序集而不得不开启trustworthy方法

​前文中提到有提到,当SQL Server 数据库开启trustworthy时,存在着用户提升权限的风险。那么,我们是不是直接查出开启trustworthy的数据库,将其关闭就解决风险了呢?如下脚本可以直接关闭实例下所有开启trustworthy数据库的trustworthy属性:

  1. use master
  2. go
  3. declare @sql varchar(max)
  4. set @sql=''
  5. select @sql=@sql+'alter database '+ QUOTENAME(name,'[')+' set trustworthy ' +' off '
  6. from sys.databases
  7. where is_trustworthy_on=1
  8. print @sql
  9. --exec(@sql)

有心的朋友可能已经注意到,上面脚本的最后一句是注释掉的,我们是不能直接执行这个脚本的(重要的事情说三篇,不能直接执行!不能直接执行!不能直接执行!,我们必须确认数据库上是否有需要开启trustworthy的内容,如程序集。

    带有EXTERNAL_ACCESS 或 UNSAFE的程序集能正常执行的方案有两种:

  1. 开启数据库trustworthy,保证数据库拥有者有程序集 [EXTERNAL ACCESS] 或者 [UNSAFE] 权限。

  2.  程序集已使用其对应登录名具有 EXTERNAL ACCESS ASSEMBLY 权限的证书或非对称密钥加以签名。

考虑到前文中提到的安全隐患,如果数据库中存在着带有EXTERNAL_ACCESS 或 UNSAFE的程序集,并且数据库的trustworthy为开启状态,我们就需要采用方案2来代替方案1,消除安全隐患,下面我将分享方案2的处理步骤。

 

为ddl加强名称签名

强名称签名的私钥公钥生成

本文中是使用Windows强名称签名工具sn生成私钥和公钥的,首先我们需要到目录 :

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools 下查找是否有sn工具,没有的话,就要另外安装,如果存在,以管理员身份打开CMD,切换到上面对应目录下:

使用强名称工具sn生成私钥、公钥的具体脚本及步骤如下:

最终将生成的私钥pri.snk 拷贝到项目文件中

在VS解决方案资源管理器中,右击项目名称→属性

在弹出的属性列表中选择“签名”→勾选为程序集签名,找到前面生成的私钥文件,这里是pri.snk:

最后重新生成dll,到此完成程序集的强名称签名。

将dll 部署到SQL Server数据库

下面我将给出将强名称签名的程序集部署到数据库上的脚本,并进行测试,如下:

  1. use DB1
  2. go
  3. exec sp_configure 'show advanced options',1
  4. go
  5. reconfigure
  6. go
  7. exec sp_configure 'clr enabled',1
  8. reconfigure with override
  9. exec sp_configure 'show advanced options',0
  10. go
  11. reconfigure
  12. go
  13. USE master --这个数据库一定是master
  14. --创建非对称密钥
  15. CREATE ASYMMETRIC KEY SQLCLRTestKey FROM EXECUTABLE FILE = 'D:\TgSQLPlus\Skew.dll'
  16. --创建登录名
  17. CREATE LOGIN SQLCLRTestLogin FROM ASYMMETRIC KEY SQLCLRTestKey
  18. --把权限授予给该登录名
  19. GRANT EXTERNAL ACCESS ASSEMBLY TO SQLCLRTestLogin;
  20. USE DB1
  21. --创建程序集
  22. create ASSEMBLY DescriptiveStatistics from
  23. 'D:\TgSQLPlus\Skew.dll'
  24. with PERMISSION_SET=EXTERNAL_ACCESS;
  25. --创建用户定义函数(UDF)
  26. CREATE AGGREGATE dbo.Skew(@s float)
  27. returns float
  28. external name DescriptiveStatistics.Skew;
  29. create table test (name varchar(60),id bigint)
  30. --测试
  31. insert into test
  32. select top 100 name,object_id
  33. from sys.objects
  34. go 10
  35. with CustomerSalesCTE as
  36. (
  37. select
  38. name
  39. ,SUM(id) as TotalAmount
  40. from test
  41. group by name
  42. )
  43. select
  44. ROUND(avg(TotalAmount),2) as Average
  45. ,ROUND(STDEV(TotalAmount),2) as StandardDeviation
  46. ,ROUND(dbo.Skew(cast(TotalAmount as decimal(30,2))),6) as Skewness
  47. from CustomerSalesCTE
  48. --确认trustworthy是否启用
  49. select name,is_trustworthy_on from sys.databases
  50. where name='DB1'

测试发现trustworthy关闭状态,自定义函数正常运行。

注意:

  • 如果两个程序集使用同一个私钥进行签名,在master库创建非对称秘钥时,会报如下错误:

消息 15396,级别 16,状态 1,第 103 行 名为 '' 的非对称密钥已存在,或已将此非对称密钥添加到该数据库中。

  • 在trustworthy关闭状态下,要先在master库创建非对称秘钥,使用非对称秘钥创建登陆名,并赋予[EXTERNAL ACCESS]权限,然后再在指定数据库中创建程序集,顺序不能颠倒,否则会报如下错误:

消息 10327,级别 14,状态 1,第 111 行

针对程序集 'DatabaseKurt' 的 CREATE ASSEMBLY 失败,因为程序集 'DatabaseKurt' 未获授权,不满足 PERMISSION_SET = EXTERNAL_ACCESS。满足以下两个条件之一时将给程序集授权: 数据库所有者(DBO)拥有 EXTERNAL ACCESS ASSEMBLY 权限,且数据库具有 TRUSTWORTHY 数据库属性;或者,程序集已使用其对应登录名具有 EXTERNAL ACCESS ASSEMBLY 权限的证书或非对称密钥加以签名。

  • 登陆账户的权限如果和创建程序集PERMISSION_SET选项不一致,即赋予账户[EXTERNAL ACCESS],PERMISSION_SET=UNSAFE,或者相反时,创建程序集亦会出现如下错误:

消息 10327,级别 14,状态 1,第 111 行

针对程序集 'DatabaseKurt' 的 CREATE ASSEMBLY 失败,因为程序集 'DatabaseKurt' 未获授权,不满足 PERMISSION_SET = UNSAFE。满足以下两个条件之一时将给程序集授权: 数据库所有者(DBO)拥有 UNSAFE ASSEMBLY 权限,且数据库具有 TRUSTWORTHY 数据库属性;或者,程序集已使用其对应登录名具有 UNSAFE ASSEMBLY 权限的证书或非对称密钥加以签名。

最后如果测试发现报如下错误:

消息 10314,级别 16,状态 4,第 74 行

在尝试加载程序集 ID 65544 时 Microsoft .NET Framework 出错。服务器可能资源不足,或者不信任该程序集,因为它的 PERMISSION_SET 设置为 EXTERNAL_ACCESS 或 UNSAFE。请重新运行查询,或检查有关的文档了解如何解决程序集信任问题。有关此错误的详细信息:

System.IO.FileLoadException: 未能加载文件或程序集“databasekurt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=5db4a667503bfd56”或它的某一个依赖项。发生与安全有关的错误。 (异常来自 HRESULT:0x8013150A)

System.IO.FileLoadException:

   在 System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

   在 System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

   在 System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)

   在 System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)

   在 System.Reflection.Assembly.Load(String assemblyString)

我们需要从头检查各个步骤是否完成。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
SQL Server数据库还原或分离附加后程序集遇到的SQL CLR问题
在SQL Server引用dll的流程
Sql2008中添加程序集.
ODAC(V9.5.15) 学习笔记(三)TOraSession(3)
数据库中的实例名和数据库名有什么不同?
安装Radmanager时找不到数据库
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服