【问题标题】:How to execute sp_send_dbmail while limiting permissions如何在限制权限的同时执行 sp_send_dbmail
【发布时间】:2009-02-09 22:23:59
【问题描述】:

有没有一种方法可以让我的数据库中的用户访问执行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'.

谢谢!

【问题讨论】:

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


    【解决方案1】:

    你的方法没问题,但你的包装程序必须在 msdb 数据库中。 然后,执行“EXEC msdb.dbo._TestSendMail”

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

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

    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
    

    【讨论】:

      【解决方案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
      
      */
      

      【讨论】:

        【解决方案3】:

        一种可能的解决方案是将邮件封装为存储过程,例如mail_error_as_MAILER(您稍后会调用) 和另一个存储过程 例如

        
        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(您可以控制他们可以放入的内容)并让代理帐户定期发送这些邮件

        或者:允许他们邮寄,但在滥用时使用带有生锈尖刺的大棒

        【讨论】:

          猜你喜欢
          • 2011-08-09
          • 2022-08-17
          • 2016-12-05
          • 1970-01-01
          • 1970-01-01
          • 2011-08-29
          • 1970-01-01
          • 2018-04-23
          相关资源
          最近更新 更多