sp_send_mail的数据库权限出现问题


8

我正在尝试发送数据库邮件,但是却收到了EXECUTE permission denied on the object 'sp_send_dbmail' database 'msdb', schema 'dbo'.。我正在运行的代码如下:

SELECT SUSER_NAME(), USER_NAME();
Create USER kyle_temp FOR LOGIN Foo
EXECUTE AS USER = 'kyle_temp';
SELECT SUSER_NAME(), USER_NAME();
EXEC msdb.dbo.sp_send_dbmail @profile_name = 'Mail Profile',
            @recipients = 'test@test.com',
            @subject = 'Test',
              @body = 'Test'
REVERT;
DROP USER kyle_temp

Foo登录显示它已映射到msdb中的Foo用户。当我查看msdb中的foo用户时,我看到它已检查“ DatabaseMailUserRole”,并且对dbo执行sp_send_dbmail

我想念什么?

Answers:


10

您正在进入EXECUTE AS上下文的可怕的“沙盒”模式,如使用EXECUTE AS扩展数据库模拟中所述。简而言之,EXECUTE AS USER ...仅在数据库上下文内部而不在实例上下文信任在下面运行的代码。

有三种解决方法:

  • 简单方法:将当前数据库标记为TRUSTWORTHY ALTER DATABASE [...] SET TRUSTWORTHY ON;
  • 正确的出路:使用代码签名
  • 作弊:使用 EXECUTE AS LOGIN

如果在您的环境dbo中当前数据库的可信,则可以使用TRUSTWORTHY。它将起作用,但是如果设置了此属性db_owner,则当前数据库中的任何属性都可以将其提升为服务器管理员。

如果您想要一个“正确”的解决方案,那么:

  1. 将此代码移到存储的proc中
  2. 用证书签署存储的过程
  3. 删除私钥(这样就永远不能再次使用它来签名)
  4. 导出公钥,将其导入 [msdb]
  5. [msdb]从此证书派生用户
  6. 向证书派生用户授予必要的权限(AUTHENTICATE,对sp_send_mail执行EXECUTE)

小事,对吗?顺便说一句,每次您修改已签名的存储过程时,签名都会丢失,必须重复该过程。有关示例,请参见从已激活的过程调用另一个数据库中的过程

我完全不建议使用EXECUTE AS LOGIN代替。


从长远来看,我试图将其作为触发器执行,所以我的EXECUTE AS是短期内进行测试的一种方法...
Kyle Brandt 2012年

1
最干净的方法是在数据库中有一个本地存储的proc,并msdb.dbo.sp_send_mail在此本地SP主体中进行调用。让触发器调用此本地SP。对SP进行代码签名。
Remus Rusanu 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.