我正在寻找一种解决方案,其中用户仅允许其执行a过程。在下面的示例中,该过程是
lowlevel.ZipFile
(主过程)。问题是该过程本身执行其他过程,从而导致错误。只要用户执行“主过程”而不是任何嵌套过程本身,我希望它获得批准。
我环顾四周,发现拒绝访问执行其他存储的最简单方法是创建一个新模式。然后,我创建了另一个有权访问嵌套过程的用户,并创建了我的 main procedure WITH EXECUTE AS
签名给具有访问权限的用户。但是,当我与该用户执行主程序时,他突然没有执行嵌套程序的权限? 下面的代码用于测试目的。 请注意
,如果您在主数据库中有名为“SiteDatabase44”的数据库、名为“LowLevelUser_Executor”的用户或名为“___ZipFile”的过程。最后注释了清理脚本。
SET NOCOUNT ON
USE master;
IF NOT EXISTS(SELECT 1 FROM sys.databases WHERE Name = 'SiteDatabase44')
EXECUTE('CREATE DATABASE SiteDatabase44')
IF NOT EXISTS (SELECT 1 FROM sys.syslogins WHERE NAME = 'LowLevelUser_Executor')
BEGIN
CREATE LOGIN [LowLevelUser_Executor] WITH PASSWORD = N'ShouldNeverBeLoggedInAs_asdasd', CHECK_POLICY = OFF;
GRANT CONNECT SQL TO [LowLevelUser_Executor]
END
GO
CREATE OR ALTER PROCEDURE dbo.___ZipFile
@Filepath varchar(500) NULL
AS
SELECT 22
GO
IF NOT EXISTS(SELECT 1 FROM sys.sysusers WHERE name = 'LowLevelUser_Executor')
CREATE USER LowLevelUser_Executor FOR LOGIN LowLevelUser_Executor WITH DEFAULT_SCHEMA = dbo
GRANT EXECUTE ON [dbo].___ZipFile TO [LowLevelUser_Executor]
USE [SiteDatabase44];
IF NOT EXISTS(SELECT 1 FROM sys.schemas WHERE [name] = 'lowlevel')
EXECUTE('CREATE SCHEMA lowlevel')
GO
IF NOT EXISTS(SELECT 1 FROM sys.sysusers WHERE name = 'LowLevelUser_Executor')
CREATE USER [LowLevelUser_Executor] FOR LOGIN [LowLevelUser_Executor] WITH DEFAULT_SCHEMA = dbo
GO
CREATE OR ALTER PROCEDURE lowlevel.ZipFile
@Filepath varchar(500) NULL
WITH EXECUTE AS 'LowLevelUser_Executor'
AS
SELECT 'Zipping file...'
EXECUTE master.dbo.___ZipFile @Filepath
GO
GRANT SELECT, EXECUTE ON SCHEMA::lowlevel TO [LowLevelUser_Executor] WITH GRANT OPTION;
EXECUTE AS LOGIN = 'LowLevelUser_Executor'
exec master.dbo.___ZipFile @Filepath = '' -- Works as expected
EXECUTE [lowlevel].ZipFile @Filepath = '' -- Doesn't work? Get's this error: The EXECUTE permission was denied on the object '___ZipFile', database 'master', schema 'dbo'.
go
REVERT;
/*
CLEAN UP
USE MASTER;
DROP DATABASE SiteDatabase44
GO
DROP PROCEDURE dbo.___ZipFile
GO
DROP USER [LowLevelUser_Executor]
GO
DROP LOGIN [LowLevelUser_Executor]
*/
进行配置,但这样的设置会带来(多个)安全隐患,因此在不了解您的环境的情况下,我不能推荐它。
因此,另一种选择是实施证书。这是一个简化的示例,例如,您可能希望/需要使用密码加密您的证书。如果这样做,则在第二个数据库中创建私钥时,需要将私钥传递给 CREATE CERTIFICATE
语句(可以使用
CERTPRIVATEKEY
步骤;您可能需要更具体的以满足您的需求。首先,让我们创建几个测试数据库和一个测试登录:
USE master;
GO
CREATE DATABASE SomeDatabase;
GO
CREATE LOGIN AnotherLogin WITH PASSWORD = '123abc*()';
GO
CREATE DATABASE AnotherDatabase;
GO
现在我将在两个数据库中创建一个过程,一个引用另一个数据库。然后我将创建一个
USER
来测试
LOGIN
并授予他们
GRANT
引用另一个过程的权限 EXECUTE
:USE SomeDatabase;
GO
CREATE PROC dbo.SomeProc AS
BEGIN
SELECT [name]
FROM sys.objects;
END;
GO
USE AnotherDatabase;
GO
CREATE PROC dbo.AnotherProc AS
BEGIN
EXEC SomeDatabase.dbo.SomeProc;
END;
GO
CREATE USER AnotherUser FOR LOGIN AnotherLogin;
GO
太好了,现在我们有了与您类似的设置。我们现在可以测试看看事情是否有效(他们不会):
GRANT EXECUTE ON dbo.AnotherProc TO Anotheruser;
GO
EXECUTE AS LOGIN = 'AnotherLogin'
GO
EXEC dbo.AnotherProc --Fails, no access to the other database
GO
REVERT;
GO
消息 916,级别 14,状态 2,过程 dbo.AnotherProc,第 5 行 [批处理起始行 32]
服务器主体“AnotherLogin”无法在当前安全上下文下访问数据库“SomeDatabase”。
所以是的,这是预料之中的。
那么,让我们创建一个证书。由于这是一个新的测试数据库,我需要创建一个
MASTER KEY
,但这很可能已经存在于您的数据库中(如果存在,您不需要再次创建一个,但出于这里的目的,我这样做)。然后我还签署了我们之前创建的程序。
如前所述,证书未加密,但这是您可能想要/需要做的事情。
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'abc123!"£'; --As this is a new db, we need a master key. Obviously you'd use a better password
GO
--Create a cert
CREATE CERTIFICATE AnotherCert WITH SUBJECT = N'Allow Cross Database Queries between AnotherDB and SomeDB';
GO
ADD SIGNATURE TO dbo.AnotherProc BY CERTIFICATE AnotherCert;
GO
太好了,但现在我们还需要在 other数据库中创建该证书。幸运的是,这比 SQL Server 2008 时代要容易得多,我们可以使用
CERTENCODED
获取证书的二进制值。然而,由于 CREATE CERTIFICATE
需要一个文字值,我们将获取该值并将其连接到“动态”批处理,并使用
sys.sp_executesql
执行该批处理。 像以前一样,因为这是一个测试,它会创建一个
MASTER KEY
,但您很可能不需要这样做。
DECLARE @CertBinary varbinary(8000) = CERTENCODED(CERT_ID(N'AnotherCert'));
DECLARE @SQL nvarchar(MAX) = N'CREATE MASTER KEY ENCRYPTION BY PASSWORD = ''abc123!"£'';' + NCHAR(13) + NCHAR(10) + --As this is a new db, we need a master key. Obviously you'd use a better password
N'CREATE CERTIFICATE AnotherCert FROM BINARY = ' + CONVERT(varchar(8000),@CertBinary,1) + N';';
EXEC SomeDatabase.sys.sp_executesql @SQL; --Will create in SomeDatabase
GO
太好了,我们几乎就到了。最后,我们需要根据另一个数据库中的证书创建一个
USER
SomeDatabase
,并为数据库中的
USER
LOGIN
创建一个 AnotherLogin
。但请注意,我没有向 USER
授予任何权限,但它们仍然需要能够连接到其他数据库。最后,我将证书的 USER
权限授予 EXECUTE
程序,(注意它不是 AnotherUser
)。
CREATE USER AnotherCertUser FROM CERTIFICATE AnotherCert;
CREATE USER AnotherUser FROM LOGIN AnotherLogin; --They still need to exist in the DB, edven if they have no access
GO
GRANT EXECUTE ON dbo.SomeProc TO AnotherCertUser;
好的,我们现在可以再次测试了:
USE AnotherDatabase;
GO
EXECUTE AS LOGIN = 'AnotherLogin'
GO
EXEC dbo.AnotherProc --Works, permissions of tbhe certificate are used
GO
EXEC SomeDatabase.dbo.SomeProc; --To demonstrate it doesn't work.
GO
REVERT;
GO
成功!该过程执行
callsSomeDatabase.dbo.SomeProc
的过程,但直接调用该过程失败。
清洁:
USE master;
GO
DROP DATABASE SomeDatabase;
DROP DATABASE AnotherDatabase;
DROP LOGIN AnotherLogin;
当然,另一种方法是只授予
LOGIN
中 USER
的
master
执行 dbo.___ZipFile
的权限,但看来您明确 不想想要这样做。