为什么具有sysadmin权限的用户不能以EXECUTE AS用户身份访问msdb?

时间:2019-03-30 18:20:00

标签: sql-server

我创建了一个testuser登录集,设置为sysdamin,并将其用于在execute as以外的测试数据库中创建的以下函数中的子句msdb

CREATE FUNCTION [dbo].[MyTestFunction] 
    (@job_name SYSNAME)
RETURNS INT
WITH EXECUTE AS 'TestUser'
AS
BEGIN
    DECLARE @id INT 

    SELECT TOP 1 @id = schedule_id 
    FROM msdb.dbo.sysjobschedules

    RETURN @id
END

执行MyTestFunction时出现以下错误:

  

对对象'sysjobschedules',数据库'msdb',模式'dbo'的SELECT权限被拒绝。

作为更改,如果我直接使用TestUser登录名并使用测试数据库直接执行SELECT语句,它将正常工作。

用户TestUser可以直接从测试数据库访问msdb,但是如果在测试数据库功能的msdb子句中使用,则不能访问execute as

如何从另一个数据库中创建的函数访问msdb数据库?

预先感谢

Ignacio

1 个答案:

答案 0 :(得分:0)

已将EXECUTE AS模拟的安全上下文沙箱化到当前数据库。除非数据库为TRUSTWORTHY,否则您将无法访问函数中的其他数据库,这通常不是一个好习惯。

对于最低特权用户的跨数据库访问,请考虑使用module signing。这使您可以在模块执行上下文中授予对其他数据库和对象的访问权限,而无需授予最终用户直接权限。用户只需要对该功能的权限。

下面是从参考文章中收集的示例脚本,可满足您的特定需求。尽管可以扩展此基本技术以提供sysadmin权限,但是最佳实践是使用最低特权帐户。

-- Create a certificate in msdb
USE msdb;
CREATE CERTIFICATE msdb_certificate
   ENCRYPTION BY PASSWORD = 'p@Ss0RDforTheceRT1cate'
   WITH SUBJECT = 'For cross-database access to msdb database';

-- create a user from certification with needed permissions
CREATE USER msdb_certificate_user FROM CERTIFICATE msdb_certificate;
GRANT SELECT ON msdb.dbo.sysjobschedules TO msdb_certificate_user;

-- Copy certificate to user database (Example)
DECLARE @cert_id int = cert_id('msdb_certificate');
DECLARE @public_key  varbinary(MAX) = certencoded(@cert_id),
        @private_key varbinary(MAX) =
           certprivatekey(@cert_id,
              'p@Ss0RDforTheceRT1cate',
              'p@Ss0RDforTheceRT1cate');
DECLARE @sql nvarchar(MAX) =
      'CREATE CERTIFICATE msdb_certificate
       FROM  BINARY = ' + convert(varchar(MAX), @public_key, 1) + '
       WITH PRIVATE KEY (BINARY = ' +
          convert(varchar(MAX), @private_key, 1) + ',
          DECRYPTION BY PASSWORD = ''p@Ss0RDforTheceRT1cate'',
          ENCRYPTION BY PASSWORD = ''p@Ss0RDforTheceRT1cate'')';
EXEC YourDatabase.sys.sp_executesql @sql;
ALTER CERTIFICATE msdb_certificate REMOVE PRIVATE KEY; --remove ephemeral private key
GO

--sign module with certificate 
USE YourDatabase;
ADD SIGNATURE TO dbo.MyTestFunction BY CERTIFICATE msdb_certificate
   WITH PASSWORD = 'p@Ss0RDforTheceRT1cate';
ALTER CERTIFICATE msdb_certificate REMOVE PRIVATE KEY; --remove ephemeral private key
GO
--users only need permissions on directly invoked module
GRANT EXECUTE ON dbo.MyTestFunction TO YourUser;
GO