很高兴您解决了此问题,但是不建议使用所有权链接。由于您似乎确实担心所涉及权利的安全性和正确性,因此我添加了此回复(尽管很晚),以作为正在发生的事情以及如何解决此问题的参考。
EXECUTE AS模拟范围
EXECUTE AS子句有两种形式:EXECUTE AS LOGIN和EXECUTE AS USER。EXECUTE AS LOGIN由服务器进行身份验证,并且是整个SQL实例(服务器范围)信任的模拟上下文:
当使用EXECUTE AS LOGIN语句来模拟主体时,或者在使用EXECUTE AS子句在服务器范围内的模块中模拟时,模拟的范围是在服务器范围内。这意味着在上下文切换之后,可以访问服务器中具有模拟登录名权限的任何资源。
EXECUTE AS USER由数据库认证,是仅该数据库(数据库范围)信任的模拟上下文:
但是,当使用EXECUTE AS USER语句模拟主体时,或者在使用EXECUTE AS子句在数据库范围内的模块中模拟时,默认情况下,模拟的范围仅限于数据库。这意味着对数据库范围之外的对象的引用将返回错误。
具有EXECUTE AS子句的存储过程将创建数据库范围的模拟上下文,因此将无法引用数据库外部的对象,在这种情况下您将无法引用,msdb.dbo.sp_start_job
因为in中msdb
。还有许多其他示例,例如尝试访问服务器范围DMV,尝试使用链接的服务器或尝试将Service Broker消息传递到另一个数据库中。
使数据库范围内的模拟访问资源通常是不允许模拟角色上下文的身份验证者所必须访问的资源。对于数据库范围的模拟,验证者是数据库dbo。这可以通过两种可能的方式实现:
- 通过在对模拟环境进行身份验证的数据库(即发出EXECUTE AS子句的数据库)上打开TRUSTWORTHY属性。
- 通过使用代码签名。
在MSDN:使用EXECUTE AS扩展数据库模拟中描述了这些详细信息。
通过跨数据库所有权链接解决此问题时,您已在整个服务器级别启用了跨数据库链接,这被认为存在安全风险。要获得所需结果的最受控,最细粒度的方法是使用代码签名:
- 在应用程序数据库中创建一个自签名证书
dbo.StartAgentJob
用此证书签名
- 删除证书的私钥
- 将证书导出到磁盘
- 将证书导入到
msdb
- 从导入的证书中创建派生用户
msdb
- 向中的派生用户授予AUTHENTICATE权限
msdb
这些步骤确保了dbo.StartAgentJob
现在可以信任该过程的EXECUTE AS上下文msdb
,因为该上下文是由具有AUTHENTICATE权限的主体签名的msdb
。这解决了一半的难题。另一半实际上是将EXECUTE权限授予msdb.dbo.sp_start_job
现在受信任的模拟上下文。有几种方法可以做到这一点:
- 将模拟的用户
agentProxy
用户映射到,msdb
并授予他执行权限msdb.dbo.sp_start_job
- 向
msdb
身份验证者证书派生用户授予执行权限
- 向该过程添加新的签名,为其派生一个用户,并将
msdb
执行权限授予该派生的用户
选项1.很简单,但有一个很大的缺点:agentProxy
用户现在可以按msdb.dbo.sp_start_job
自己的意愿执行,他被真正授予访问权限msdb
并具有执行权限。
选项3肯定是正确的,但我认为这是不必要的过大杀伤力。
因此,我建议使用方法2:将授予对在msdb.dbo.sp_start_job
中创建的证书派生用户的执行权限msdb
。
这是对应的SQL:
use [<appdb>];
go
create certificate agentProxy
ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y'
with subject = 'agentProxy'
, start_date='01/01/2009';
go
ADD SIGNATURE TO OBJECT::[StartAgentJob]
BY CERTIFICATE [agentProxy]
WITH PASSWORD = 'pGFD4bb925DGvbd2439587y';
go
alter certificate [agentProxy]
remove private key;
go
backup certificate [agentProxy]
to file='c:\temp\agentProxy.cer';
go
use msdb
go
create certificate [agentProxy]
from file='c:\temp\agentProxy.cer';
go
create user [agentProxyAuthenticator]
from certificate [agentProxy];
go
grant authenticate to [agentProxyAuthenticator];
grant execute on msdb.dbo.sp_start_job to [agentProxyAuthenticator];
go
use [<appdb>];
go
exec dbo.StartAgentJob;
go
我的博客中有一些涉及此主题的文章,是在Service Broker激活过程的上下文中编写的(因为它们需要EXECUTE AS子句):
顺便说一句,如果您要测试我的剧本,并且生活在东半球或英国的夏季,请务必在测试之前阅读我链接的最后一篇文章。