我正在直接在SQL Server 2017上为公司软件的新版本设置安全登录系统。我试图撤消用户帐户对任何数据库的CONNECT权限,直到用户使用以下命令登录到初始身份验证数据库为止设置用户名/密码,并使用登录过程在特定数据库上启用其帐户,然后客户端将与初始数据库断开连接,并使用其个人帐户重新连接,从而连接至目标数据库。
在初始数据库中创建了一个证书,该证书用于对调用以下所示过程的过程进行签名。下面显示的过程没有任何证书的签名。创建的证书已复制到目标数据库,并用于创建一个用户,该用户然后被添加到一个具有执行以下所示过程权限的组Certified
,并具有CONNECT WITH GRANT OPTION
在数据库上。执行以下过程时,grant / revoke语句失败,表示授予者没有必要的权限(或者未找到用户/角色,这取决于我是否尝试添加AS子句)
在目标数据库中,通过存储过程中的动态SQL来完成对连接权限的授予/吊销(每个属于我们软件的数据库都具有相同的过程来完成此工作)。如果我以sysadmin固定角色的成员身份运行代码,则该方法有效,但当我使用设置的身份验证帐户运行该代码时,该方法无效。目标数据库(ModifyUser
)中的过程是从初始数据库中另一个用证书签名的过程中调用的,目标数据库中具有该角色成员的同一证书中的用户来自该过程已授予Certified
的{{1}},但是每当我运行该过程时,该语句就会失败。
我尝试了3个版本,更改了AS子句的内容:
CONNECT WITH GRANT OPTION
uCompCompID
的一部分
Certified
授予选项的角色成员的证书用户身份运行查询。 CONNECT
过程很短,因此我将在下面介绍整个过程。此过程与我要授予/撤消ModifyUser
权限的用户存储在同一数据库中,但是需要使用由与该数据库中创建的用户匹配的证书签名的其他数据库来调用该过程。
这是版本3,其中没有AS子句。
CONNECT
预期结果是目标用户的PROCEDURE [Authorization].[ModifyUser]
@user nvarchar(128),
@status bit
AS
BEGIN
SET NOCOUNT ON
IF @user IS NULL
THROW 50002, 'Invalid argument: @user', 0
IF LTRIM(RTRIM(@user)) = ''
THROW 50002, 'Invalid argument: @user', 1
IF @status IS NULL
THROW 50002, 'Invalid argument: @status', 0
DECLARE @statement nvarchar(200)
IF @status = 1
SET @statement = 'GRANT CONNECT TO ' + @user
ELSE
SET @statement = 'REVOKE CONNECT TO ' + @user
EXEC (@statement)
END
权限已更改,但是接收到的结果始终是错误。确切的错误取决于所使用的版本:
如果我直接授予证书用户权限,这不是问题。但是,我想将权限保留在一个角色中,以便在修改此系统涉及的过程之一之后不可避免地需要重新创建证书时,我只需要担心将新的证书用户添加到适当的组中,而不用担心。每次进行更改时都需要向重新创建的用户授予权限,这需要注销任何证书。
答案 0 :(得分:0)
首先,您应该更新您的问题,因为尚不清楚您在哪个数据库中创建了certificate
,哪个过程是签名的,哪个不是:
目标数据库(ModifyUser)中的过程从 初始数据库中用签名的另一个过程 证书中存在相同证书的用户 目标数据库,该角色是已认证角色的成员 授予CONNECT WITH GRANT OPTION
由此看来,只有初始数据库中的过程才用
execute as
,但是内部过程(在目标数据库中)不是,在这种情况下,只有外部过程才具有从证书创建的用户的权限,这就是为什么会出现错误N3
Grantor没有GRANT权限
在其他情况下,由于使用user
子句(此子句仅允许login
而不允许database
!)而导致错误。使用它时,您的proc将在创建过程的sysadmin
内进行沙箱处理,即,即使您是login
,也无法在另一个数据库中执行任何操作,服务器无法使用相应的{{1} }(以在其他数据库中搜索相应的user
),除非该数据库为trustworthy
,并且owner
的另一个数据库中没有authenticate
。
答案 1 :(得分:0)
我已经为我的案件解决了这个问题。要找到解决方案,请跳至水平换行符。
为了弄清楚我的原始帖子设置不好,我有一个数据库Initial
,该数据库创建了一个证书cCompCompID
,该证书用于签署过程相同的数据库。然后将证书复制到另一个数据库Target
,在该数据库中,该证书用于创建用户uCompCompID
,然后将其添加到角色Certified
中。授予该角色执行ModifyUser
和CONNECT WITH GRANT OPTION
的权限,以便ModifyUser
可以用于更改其他用户的连接权限,但仅当从{ {1}}(这是模块签名的属性,我正在使用它来确保系统尽可能地安全,以防止意外访问这些过程)。
我想保留对角色Initial
的权限,而不是对用户的权限,因为我知道以后需要修改程序,而这将需要Certified
中的程序被辞职,我将需要创建一个新证书来对过程进行签名,然后将新证书复制到Initial
数据库中,删除并重新创建用户,然后我需要担心授予权限再次权限。保留角色权限可以简化流程。证书需要重新创建,因为我所看到的所有地方,建议的操作步骤是:一旦使用完证书,就不要从证书中删除私钥,以防止以后意外使用它们。
授予角色具有Target
的权限的正确方法是在Grant语句的末尾使用GRANT OPTION
。 documentation on granting permissions on a database with an AS clause解释了我原始帖子中案例2不能正常工作的原因。在授予,撤消或拒绝作为数据库角色的权限时,执行该语句的用户必须具有:
对角色具有ALTER权限,db_securityadmin固定数据库角色的成员资格,db_owner固定数据库角色的成员资格或sysadmin固定服务器角色的成员资格。
我的问题的解决方案是向证书用户AS <role name>
授予uCompCompID
ALTER权限,以便它可以使用其角色成员身份授予或撤消该权限。向用户授予此权限不会造成安全威胁,因为仅当Certified
中由同一证书签名的过程调用ModifyUser
时才授予uCompCompID
的权限。 Initial
是从中创建的。如果它是直接调用的,或者通过未由该证书签名的任何过程调用的,则将不具有这些权限,这要归功于模块签名(而且由于uCompCompID
中的过程签名后,私钥已从证书中删除不会被其他任何人签名以创建安全威胁而没有其他地方更大的漏洞的风险)
正如@sepupic指出的那样,我还需要使用相同的证书对Initial
进行签名才能获得许可。 ModifyUser
最初具有其权限,因为它是通过使用证书签名的其他过程调用的。当ModifyUser
未经签名而执行动态SQL时,这些额外的权限将被删除,直到动态SQL完成。如果ModifyUser
用相同的证书签名,则ModifyUser
执行的动态SQL将保留预期和必需的权限。
感谢@BenThul和@sepupic的帮助。