Ed *_*ick 9 sql sql-server sql-server-2005
我们的开发人员需要能够从他们的 .Net 代码启动 SQL Server 代理作业。我知道我可以调用msdb..sp_start_job来做到这一点,但我不想让一般用户帐户直接访问运行作业。
我想要做的是使用 WITH EXECUTE AS 子句在应用程序的数据库中创建一个存储过程来模拟代理帐户。我们的程序是:
CREATE PROCEDURE dbo.StartAgentJob
WITH EXECUTE AS 'agentProxy'
AS
BEGIN
EXEC msdb.dbo.sp_start_job N'RunThisJob';
END
Run Code Online (Sandbox Code Playgroud)
但是,当我们运行它时,我们会收到以下消息:
The EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?这甚至是在 SQL2005 中执行此操作的最佳方法吗?
我很高兴你解决了这个问题,但所有权链接不是推荐的解决方案。由于您似乎非常关心所涉及权利的安全性和适当的粒度,因此我添加了此回复,尽管很晚,但作为对正在发生的事情以及如何解决此问题的参考。
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
因为在msdb
. 还有许多其他示例可用,例如尝试访问服务器范围的 DMV、尝试使用链接服务器或尝试将 Service Broker 消息传递到另一个数据库。
使数据库范围的模拟能够访问通常不允许的资源,模拟上下文的身份验证器必须是可信的。对于数据库范围的模拟,身份验证器是数据库 dbo。这可以通过两种可能的方式实现:
这些详细信息在 MSDN:使用 EXECUTE AS 扩展数据库模拟中进行了描述。
当您通过跨数据库所有权链接解决问题时,您已在整个服务器级别启用了跨数据库链接,这被视为存在安全风险。实现预期结果的最可控、最细粒度的方法是使用代码签名:
dbo.StartAgentJob
用这个证书签署msdb
msdb
msdb
这些步骤确保过程的 EXECUTE AS 上下文dbo.StartAgentJob
现在是可信的msdb
,因为上下文由在 中具有 AUTHENTICATE 权限的主体签名msdb
。这解决了一半的难题。另一半是实际授予msdb.dbo.sp_start_job
现在受信任的模拟上下文的 EXECUTE 权限。有几种方法可以做到这一点:
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
Run Code Online (Sandbox Code Playgroud)
我的博客中有一些涉及这个主题的文章,是在 Service Broker 激活过程的上下文中编写的(因为它们需要 EXECUTE AS 子句):
顺便说一句,如果您要测试我的脚本并且您住在东半球或英国夏令时,请务必阅读我在测试前链接的最后一篇文章。
您是否已将 agentProxy 登录名放入 msdb 数据库并授予其运行 sp_start_job 的权限?如果不是,您将需要为 msdb 数据库和您的用户数据库启用数据库权限链接。
您最好将登录名放入 msdb 数据库并授予它正确的权限。