SQL Server:存储过程的 EXECUTE AS 子句未授予系统管理员权限

Bru*_*rez 4 sql-server permissions impersonation database-permissions sql-server-2008-r2

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

问题是我的 IT 部门不允许我使用管理员用户,只能使用系统管理员用户的 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

谢谢

Sol*_*zky 5

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

  1. 连接到数据库
  2. 创建用户
  3. 改变角色

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

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

USE [master];
GO

CREATE CERTIFICATE [BackupRestoreCert]
    ENCRYPTION BY PASSWORD = N'MyPassword'
    WITH SUBJECT = N'Certificate for Managing Backup/Restore Operation Permissions';
GO
Run Code Online (Sandbox Code Playgroud)

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

CREATE LOGIN [BackupRestoreOps] FROM CERTIFICATE [BackupRestoreCert];

ALTER SERVER ROLE [sysadmin] ADD MEMBER [BackupRestoreOps];
Run Code Online (Sandbox Code Playgroud)

第 3 步:使用该证书对存储过程进行签名,创建指向新登录名的链接:

ADD SIGNATURE
    TO [dbo].[myProc]
    BY CERTIFICATE [BackupRestoreCert]
    WITH PASSWORD = 'MyPassword';
Run Code Online (Sandbox Code Playgroud)

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

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

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


免责声明
我只想/需要明确指出,鉴于问题中指定的存储过程,正如所写的那样,一旦授予此权限,允许 SQL 注入。当然,这已经是 IT 人员决定使用该EXECUTE AS子句授予sysadmin此存储过程权限的初衷的结果。我现在只是指出,上述步骤实际上将使他们的预期行为成为现实。如果动态 SQL 上方的步骤在传入数据库名称以外的任何内容时会出错,那么很好,但是对于可能希望复制此内容并且只是在不了解完整内容的情况下复制/粘贴的其他人,仍然需要说明这一点语境。

有两件事应该做:

  1. 虽然是次要的,但输入参数的数据类型应该是sysname(别名为NVARCHAR(128)),因为它是[name][sys].[databases].
  2. 主要要做的是验证传入的值是否是现有的数据库名称,大致如下:

    IF (DB_NAME(@database) IS NULL)
    BEGIN
       RAISERROR(N'Invalid Database Name', 16, 1);
       RETURN;
    END;
    
    Run Code Online (Sandbox Code Playgroud)

编辑:
我试图找到另一个服务器角色,它允许这样做,但不sysadmin希望不使用这样的特权角色。我试过dbcreator, securityadmin, serveradmin, 和setupadmin,但不幸的是他们都没有工作:(。