我开发了一个存储过程,以便从备份文件中恢复数据库并向其添加应用程序用户。此存储过程属于主数据库。
问题是我的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名称中的用户?
由于
答案 0 :(得分:3)
您面临的问题是模拟的限制(即通过EXECUTE AS
切换安全上下文)。对于数据库范围的对象(如存储过程),您在user
子句中指定数据库级EXECUTE AS
,而不是服务器级login
。因此,此过程实际上并不是sysadmin
。但是,有一种方法可以安全地授予这一个存储过程 true sysadmin
权限,这将允许它执行动态SQL中的步骤,即:
执行此操作的方法是使用证书对存储过程进行签名。然后,该证书还将用于创建将添加到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上面的步骤如果传入了除数据库名称以外的任何内容就会出错,那么很好,但是这仍然需要为其他可能想要复制它而只是复制/粘贴而不理解完整版本的人说明上下文。
应该做两件事:
sysname
(NVARCHAR(128)
的别名),因为这是[name]
中[sys].[databases]
的定义。要做的主要事情是验证传入的值是否是现有的数据库名称,类似于:
IF (DB_NAME(@database) IS NULL)
BEGIN
RAISERROR(N'Invalid Database Name', 16, 1);
RETURN;
END;
修改强>
我已经尝试找到另一个服务器角色,允许这不是sysadmin
,以期不使用这样的特权角色。我尝试了dbcreator
,securityadmin
,serveradmin
和setupadmin
,但不幸的是,他们都没有工作:(。