如何在限制权限的同时执行sp_send_dbmail

时间:2009-02-09 22:23:59

标签: sql-server-2005 stored-procedures permissions

有没有办法为我的数据库中的用户提供访问权限以执行 msdb.dbo.sp_send_dbmail 而无需将它们添加到MSDB数据库和DatabaseMailUserRole?

我试过这个:

ALTER PROCEDURE [dbo].[_TestSendMail]
(
  @To NVARCHAR(1000),
  @Subject NVARCHAR(100),
  @Body NVARCHAR(MAX)
)
WITH EXECUTE AS OWNER
AS 
    BEGIN
        EXEC msdb.dbo.sp_send_dbmail @profile_name = N'myProfile',
            @recipients = @To, @subject = @Subject, @body = @Body
    END

但是我收到了这个错误:

The EXECUTE permission was denied on the object 'sp_send_dbmail', database 'msdb', schema 'dbo'.

谢谢!

3 个答案:

答案 0 :(得分:5)

您的方法没问题,但您的包装器proc必须位于msdb数据库中。 然后,执行“EXEC msdb.dbo._TestSendMail”

这仍然会在msdb中留下dbo._TestSendMail的权限问题。 但是public / EXECUTE就足够了:它只暴露你需要的3个参数。

如有疑问,请添加WITH ENCRYPTION。这足以阻止没有sysadmin权限的任何人查看代码

USE msdb
GO
CREATE PROCEDURE [dbo].[_TestSendMail]
(
  @To NVARCHAR(1000),
  @Subject NVARCHAR(100),
  @Body NVARCHAR(MAX)
)
-- not needec WITH EXECUTE AS OWNER
AS 
    BEGIN
        EXEC dbo.sp_send_dbmail @profile_name = N'myProfile',
            @recipients = @To, @subject = @Subject, @body = @Body
    END

答案 1 :(得分:2)

您实际上可以使用证书签名存储过程来执行此操作,并且不必在msdb中执行此操作:

CREATE DATABASE TestDBMail
GO

USE [TestDBMail]
GO

CREATE PROCEDURE [dbo].[TestSendMail]
(       
        @To NVARCHAR(1000),  
        @Subject NVARCHAR(100),  
        @Body NVARCHAR(MAX)
)
WITH EXECUTE AS OWNER
AS
BEGIN
        EXEC msdb.dbo.sp_send_dbmail 
                        @profile_name = N'Database Mail Profile',
                        @recipients = @To, 
                        @subject = @Subject, 
                        @body = @Body    
END
GO

-- This should fail
EXECUTE [dbo].[TestSendMail] 'someemail@domain.com', 'test', 'body'

-- Create a certificate to sign stored procedures with
CREATE CERTIFICATE [DBMailCertificate]
ENCRYPTION BY PASSWORD = '$tr0ngp@$$w0rd'
WITH SUBJECT = 'Certificate for signing TestSendMail Stored Procedure';
GO

-- Backup certificate so it can be create in master database
BACKUP CERTIFICATE [DBMailCertificate]
TO FILE = 'd:\Backup\DBMailCertificate.CER';
GO

-- Add Certificate to Master Database
USE [master]
GO
CREATE CERTIFICATE [DBMailCertificate]
FROM FILE = 'd:\Backup\DBMailCertificate.CER';
GO

-- Create a login from the certificate
CREATE LOGIN [DBMailLogin]
FROM CERTIFICATE [DBMailCertificate];
GO

-- The Login must have Authenticate Sever to access server scoped system tables
-- per http://msdn.microsoft.com/en-us/library/ms190785.aspx
GRANT AUTHENTICATE SERVER TO [DBMailLogin]
GO

-- Create a MSDB User for the Login
USE [msdb]
GO
CREATE USER [DBMailLogin] FROM LOGIN [DBMailLogin]
GO

-- Add msdb login/user to the DatabaseMailUserRole
EXEC msdb.dbo.sp_addrolemember @rolename = 'DatabaseMailUserRole', @membername = 'DBMailLogin';
GO

USE [TestDBMail]
GO

-- Sign the procedure with the certificate's private key
ADD SIGNATURE TO OBJECT::[TestSendMail]
BY CERTIFICATE [DBMailCertificate] 
WITH PASSWORD = '$tr0ngp@$$w0rd';
GO

-- This will succeed
EXECUTE [dbo].[TestSendMail] 'someemail@domain.com', 'test', 'body'

/*
-- Cleanup
USE [msdb]
GO
DROP USER [DBMailLogin]
GO
USE [master]
GO
DROP LOGIN [DBMailLogin]
DROP CERTIFICATE [DBMailCertificate]
DROP DATABASE [TestDBMail]

-- Delete the certificate backup from disk

*/

答案 2 :(得分:1)

一种可能的解决方案是将邮件封装为存储过程,例如mail_error_as_MAILER(你稍后会打电话) 和另一个存储过程 e.g。


ALTER PROCEDURE [dbo].[mail_error](@error_ID int)
SET NOCOUNT ON
declare @rc int
declare @object int
declare @src varchar(255)
declare @desc varchar(255)
declare @osql_cmd varchar(1000)
-- create shell object
exec @rc = sp_oacreate 'wscript.shell', @object out
if @rc0 
  begin
    exec sp_oageterrorinfo @object, @src out, @desc out
    return
  END

  DECLARE @user VARCHAR(50)
  DECLARE @password VARCHAR(50)
  DECLARE @database VARCHAR(50)
  DECLARE @server VARCHAR(50)
  DECLARE @sql varchar(200) 
 SET @user=MAILER,@password=XXXXXX,@database=XXXXXX,@server=XXXXX 
SET @sql= 'EXEC mail_ERROR_as_MAILER @error_ID=' + CAST(@error_id as varchar(10))
set @osql_cmd='osql -U'+@user+' -P'+@password+' -d'+@database+' -S"'+@server+'"  -Q"'
  +@sql+'"'

exec @rc= sp_oamethod @object, 'run', null, @osql_cmd
--print @rc
if @rc0 
  begin
    exec sp_oageterrorinfo @object, @src out, @desc out
    return
  end
-- destroy shell object
exec sp_oadestroy @object

但这需要: *硬编码密码(确保用户无法查看存储过程的定义......) *让用户访问sp_oacreate等...(打开其他安全问题,例如DOS)

通过这种方式,他们只能以您希望的方式使用邮件,而不会授予他们邮寄其他内容的权限。

或更安全, 让用户将邮件放入某种mail_queue(你可以控制他们可以放入什么)并让代理人定期发送这些邮件

或者:允许他们发送邮件,但是让一个大型俱乐部滥用滥用