SQL Server:存储过程的EXECUTE AS子句不授予sysadmin权限

时间:2014-10-28 01:05:10

标签: sql-server permissions sql-server-2008-r2 impersonation database-permissions

我开发了一个存储过程,以便从备份文件中恢复数据库并向其添加应用程序用户。此存储过程属于主数据库。

问题是我的IT部门不允许我使用管理员用户,只允许使用带有sysadmin用户的EXECUTE AS语句。

我可以恢复数据库但我找不到在流程结束时添加用户的方法。

我使用的代码:

CREATE PROCEDURE [dbo].[myProc] 
@database VARCHAR(50)
WITH EXECUTE AS 'aSysAdminUser' 
AS
BEGIN
    --Restore the database (working)
    --Add the application user    (not working)                  
    SET @sqlScript = 'USE '+@database +';
    CREATE USER [myApplicationUser] FROM LOGIN [myApplicationUser];
    EXEC sp_addrolemember ''db_owner'', ''myApplicationUser'''
    EXEC(@sqlScript)
END

当我运行它时,我有以下错误消息:

  

服务器主体“aSysAdminUser”无法执行   在当前安全上下文下访问数据库“database”。

知道如何使用EXECUTE AS语句从master db上的存储过程创建动态参数db名称中的用户?

由于

1 个答案:

答案 0 :(得分:3)

您面临的问题是模拟的限制(即通过EXECUTE AS切换安全上下文)。对于数据库范围的对象(如存储过程),您在user子句中指定数据库级EXECUTE AS,而不是服务器级login。因此,此过程实际上并不是sysadmin。但是,有一种方法可以安全地授予这一个存储过程 true sysadmin权限,这将允许它执行动态SQL中的步骤,即:

  1. 连接数据库
  2. 创建用户
  3. ALTER ROLE
  4. 执行此操作的方法是使用证书对存储过程进行签名。然后,该证书还将用于创建将添加到sysadmin服务器角色的服务器级登录。然后,当任何用户/登录(对此存储过程具有EXECUTE权限)执行此过程时,它将仅通过使用相同证书进行签名来获取基于证书的登录的权限。

    第1步:[master]数据库中设置证书:

    USE [master];
    GO
    
    CREATE CERTIFICATE [BackupRestoreCert]
        ENCRYPTION BY PASSWORD = N'MyPassword'
        WITH SUBJECT = N'Certificate for Managing Backup/Restore Operation Permissions';
    GO
    

    第2步:创建登录并添加到sysadmin角色:

    CREATE LOGIN [BackupRestoreOps] FROM CERTIFICATE [BackupRestoreCert];
    
    ALTER SERVER ROLE [sysadmin] ADD MEMBER [BackupRestoreOps];
    

    步骤3:使用该证书签署存储过程,创建指向新登录的链接:

    ADD SIGNATURE
        TO [dbo].[myProc]
        BY CERTIFICATE [BackupRestoreCert]
        WITH PASSWORD = 'MyPassword';
    

    以上所有内容实际上都是在[master]数据库的上下文中完成的,尽管解释它似乎更具可读性。但是,在实践中,它将是IT人员运行一次的单个脚本。当然,如果您曾经ALTER该存储过程,则必须再次运行ADD SIGNATURE命令(即步骤3),因为在对过程定义进行任何更改时它将丢失。

    就是这样。我已经使用问题中显示的存储过程对此进行了测试,一旦我添加了签名和sysadmin角色,就创建用户并将其添加到db_owner角色。

    步骤4(可能):您可以从存储过程中删除EXECUTE AS子句。如果它确实传递了允许初始恢复操作起作用的任何权限,那么现在应该通过基于证书的登录来假定这些权限,因为它被标记为sysadmin


    <强>声明
    我只是希望/需要明确的是,根据问题中指定的存储过程,在编写时,在授予此权限后允许SQL注入。当然,这已经是IT人员决定使用EXECUTE AS子句授予此存储过程sysadmin权限的初衷。我现在只是指出它,上述步骤实际上会使他们的预期行为成为现实。如果动态SQL上面的步骤如果传入了除数据库名称以外的任何内容就会出错,那么很好,但是这仍然需要为其他可能想要复制它而只是复制/粘贴而不理解完整版本的人说明上下文。

    应该做两件事:

    1. 虽然是次要点,但输入参数的数据类型应为sysnameNVARCHAR(128)的别名),因为这是[name][sys].[databases]的定义。
    2. 要做的主要事情是验证传入的值是否是现有的数据库名称,类似于:

      IF (DB_NAME(@database) IS NULL)
      BEGIN
         RAISERROR(N'Invalid Database Name', 16, 1);
         RETURN;
      END;
      
    3. 修改
      我已经尝试找到另一个服务器角色,允许这不是sysadmin,以期不使用这样的特权角色。我尝试了dbcreatorsecurityadminserveradminsetupadmin,但不幸的是,他们都没有工作:(。