sp_send_mail 的数据库权限问题

Kyl*_*ndt 9 sql-server sql-server-2008-r2 database-mail

我正在尝试发送数据库邮件,但我收到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
Run Code Online (Sandbox Code Playgroud)

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

我错过了什么?

Rem*_*anu 10

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

有以下三种出路:

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

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

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

  1. 将此代码移动到存储过程中
  2. 使用证书签署存储过程
  3. 删除私钥(这样它就再也不能用来签署任何东西了)
  4. 导出公钥,导入 [msdb]
  5. 创建[msdb]从此证书派生的用户
  6. 向证书派生用户授予必要的权限(在 sp_send_mail 上进行身份验证、执行)

微不足道吧?顺便说一句,每次修改签名的存储过程时,签名都会丢失,并且必须重复该过程。有关示例,请参阅从激活的过程调用另一个数据库中的过程

我完全不建议使用EXECUTE AS LOGIN

  • 最干净的方法是在数据库中有一个本地存储过程,并在此本地 SP 主体中调用“msdb.dbo.sp_send_mail”。让触发器调用此本地 SP。对 SP 进行代码签名。 (2认同)