系统管理员的 CREATE DATABASE 权限被拒绝

Han*_*non 3 security sql-server sql-server-2008-r2

我正在尝试创建一个存储过程,该过程可用作创建数据库的代理,而用户无权创建数据库。请参阅限制用户组访问数据库/功能?欲了解更多信息

当我尝试执行存储过程时,SQL Server 生成一个安全错误:

Msg 262, Level 14, State 1, Line 1
CREATE DATABASE permission denied in database 'master'.
Run Code Online (Sandbox Code Playgroud)

这是代码:

CREATE LOGIN DatabaseCreator WITH PASSWORD='Pa$$w0rd'; /* REPLACE WITH A SECURE PASSWORD! */
GO
CREATE USER DatabaseCreator FOR LOGIN DatabaseCreator;
GO
EXEC sys.sp_addsrvrolemember 'DatabaseCreator','sysadmin';
GO
CREATE PROCEDURE dbo.CreateDatabase
(
    @DatabaseName SYSNAME
)
WITH EXECUTE AS 'DatabaseCreator'
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @cmd NVARCHAR(max);
    IF COALESCE(@DatabaseName,'') <> ''
    BEGIN
        SET @cmd = 'CREATE DATABASE ' + QUOTENAME(@DatabaseName) + ';' 
        EXEC sys.sp_executesql @cmd;
    END
    ELSE
    BEGIN
        SET @cmd = 'INVALID DATABASE NAME';
        RAISERROR (@cmd, 0, 1);
    END
END;
GO
EXEC master.dbo.CreateDatabase 'MyDatabaseName';
Run Code Online (Sandbox Code Playgroud)

msg 262似乎是一条通用的 Permission Denied 消息。既然DatabaseCreatorsysadmin特权,这不应该发生。除非我遗漏了什么。

Pau*_*ite 5

所述EXECUTE AS的子句CREATE PROCEDURE只能用于模拟用户(不是登录)和模拟的范围被限制为当前数据库。该sysadmin权限与登录,而不是用户相关联,因此您收到一个权限错误。

正确的授予方式 CREATE DATABASE这里是签署程序。该过程有点复杂,因为我们希望签署该过程以授予服务器级权限,但该过程的每个步骤都相当简单:

首先,创建一个证书并master使用CREATE ANY DATABASE权限登录。该证书稍后将被复制到目标数据库以允许过程签名。

USE master;
GO
CREATE CERTIFICATE CreateDatabaseCert
   ENCRYPTION BY PASSWORD = 'password'
   WITH SUBJECT = 'Create Database',
   START_DATE = '20140101',
   EXPIRY_DATE = '20141231';
GO
CREATE LOGIN CreateDatabaseLogin 
FROM CERTIFICATE CreateDatabaseCert;
GO
DENY CONNECT SQL TO CreateDatabaseLogin;
GO
GRANT CREATE ANY DATABASE 
TO CreateDatabaseLogin;
Run Code Online (Sandbox Code Playgroud)

我们现在需要将证书复制到将运行该过程的数据库中。有几种方法可以做到这一点,但最兼容的是通过文件读取和写入证书。下一步编写证书:

BACKUP CERTIFICATE CreateDatabaseCert 
TO FILE = 'C:\Temp\CreateDatabase.cer'
WITH PRIVATE KEY 
(
    FILE = 'C:\Temp\CreateDatabase.pvk',
    ENCRYPTION BY PASSWORD = 'password',
    DECRYPTION BY PASSWORD = 'password'
);
Run Code Online (Sandbox Code Playgroud)

现在我们切换到目标数据库,恢复证书,并删除临时文件:

USE Sandpit;
GO
CREATE CERTIFICATE CreateDatabaseCert
FROM FILE = 'C:\Temp\CreateDatabase.cer'
WITH PRIVATE KEY
(
    FILE = 'C:\Temp\CreateDatabase.pvk',
    ENCRYPTION BY PASSWORD = 'password',
    DECRYPTION BY PASSWORD = 'password'
);
GO
--EXECUTE sys.sp_configure 'show advanced options', 1;
--RECONFIGURE;
--EXECUTE sys.sp_configure 'xp_cmdshell', 1;
--RECONFIGURE;
EXECUTE sys.xp_cmdshell 'ERASE C:\Temp\CreateDatabase.*';
Run Code Online (Sandbox Code Playgroud)

现在创建过程,并使用证书对其进行签名:

CREATE PROCEDURE dbo.CreateDatabase
(
    @DatabaseName SYSNAME
)
WITH EXECUTE AS CALLER
AS
BEGIN

    SET NOCOUNT ON;
    DECLARE @cmd NVARCHAR(max);
    IF COALESCE(@DatabaseName,'') <> ''
    BEGIN
        SET @cmd = 'CREATE DATABASE ' + QUOTENAME(@DatabaseName) + ';' 
        EXEC sys.sp_executesql @cmd;
    END
    ELSE
    BEGIN
        SET @cmd = 'INVALID DATABASE NAME';
        RAISERROR (@cmd, 0, 1);
    END
END;
GO
ADD SIGNATURE TO dbo.CreateDatabase
BY CERTIFICATE CreateDatabaseCert
WITH PASSWORD = 'password';
Run Code Online (Sandbox Code Playgroud)

为了测试这是否有效,我们创建了一个新的登录名和仅具有执行该过程权限的用户:

CREATE LOGIN test WITH PASSWORD = 'password';
CREATE USER test FROM LOGIN test;
GRANT EXECUTE ON dbo.CreateDatabase TO test;
Run Code Online (Sandbox Code Playgroud)

测试本身:

EXECUTE AS LOGIN = 'test';
EXECUTE dbo.CreateDatabase @DatabaseName = 'NewDB';
REVERT;
Run Code Online (Sandbox Code Playgroud)

数据库创建成功。要清理,请运行以下命令:

DROP DATABASE NewDB;
DROP USER test;
DROP LOGIN test;
DROP PROCEDURE dbo.CreateDatabase;
DROP CERTIFICATE CreateDatabaseCert;
GO
USE master;
DROP LOGIN CreateDatabaseLogin;
DROP CERTIFICATE CreateDatabaseCert;
Run Code Online (Sandbox Code Playgroud)

有关权限的更多信息,请参阅Erland Sommarskog 的优秀文章