如何授予用户角色具有授予选项的权限?

Posted

技术标签:

【中文标题】如何授予用户角色具有授予选项的权限?【英文标题】:How to grant permissions that a user's role has the grant option for? 【发布时间】:2019-01-30 03:46:59 【问题描述】:

我正在为我公司的新版本软件直接在 SQL Server 2017 上设置安全登录系统。我正在尝试撤销用户帐户对任何数据库的 CONNECT 权限,直到用户使用以下命令登录到初始身份验证数据库设置用户名/密码,并使用登录程序在特定数据库上启用他们的帐户,然后客户端将断开与初始数据库的连接并使用他们的个人帐户重新连接,连接到他们的目标数据库。

在初始数据库中创建了一个证书,用于对调用如下所示的过程进行签名。下面显示的过程没有任何证书签名。将创建的证书复制到目标数据库,并用于创建用户,然后将其添加到组Certified,该组有权执行下面显示的过程,并在数据库上具有CONNECT WITH GRANT OPTION。当下面的过程被执行时,grant/revoke 语句失败,说 grantor 没有必要的权限(或者找不到用户/角色,这取决于我是否尝试添加 AS 子句)

连接权限的授予/撤销是通过目标数据库中存储过程中的动态 SQL 完成的(我们软件中的每个数据库都有相同的过程来完成这项工作)。如果我以 sysadmin 固定角色的成员身份运行代码,它就可以工作,但当我使用我的设置身份验证帐户运行它时,它就不行了。目标数据库中的过程 (ModifyUser) 是从初始数据库中的另一个过程调用的,该过程使用证书签名,目标数据库中存在来自同一证书的用户,该用户是角色 @987654324 的成员@ 已被授予 CONNECT WITH GRANT OPTION,但是每当我运行该过程时,该语句都会失败。

我试过3个版本,改变了AS子句的内容:

    作为证书用户,他是数据库角色的一部分,uCompCompID 作为数据库角色,证书用户所属,Certified SQL Server 文档似乎并不清楚在尝试授予角色具有授予选项的权限时应该使用哪一个 不带AS子句,授予作为运行动态SQL的用户的权限 这似乎以身份验证用户身份运行查询,而不是作为具有CONNECT 授予选项的角色成员的证书用户

ModifyUser 过程很短,所以我将在下面包含整个过程。此过程存储在与我要授予/撤销CONNECT 权限的用户相同的数据库中,但调用由与在同一数据库中创建的用户匹配的证书签名的不同数据库。

这是版本 3,其中没有 AS 子句。

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

预期的结果是目标用户的CONNECT 权限发生了变化,但接收到的结果始终是错误的。确切的错误取决于使用的版本:

    消息 15151,第 16 层,状态 1,第 2 行 找不到用户“uCompCompID”,因为它不存在或您没有权限。 消息 15151,第 16 层,状态 1,第 2 行 找不到用户“已认证”,因为它不存在或您没有权限。 消息 4613,第 16 级,状态 1,第 2 行 Grantor 没有 GRANT 权限。

如果我直接授予证书用户权限,这不是问题。但是,我想将权限保留在一个角色中,这样当我在修改该系统所涉及的程序之一后不可避免地需要重新创建证书时,我只需要担心将新证书用户添加到适当的组,而不是每次进行需要重新签署任何证书的更改时都需要向重新创建的用户授予权限。

【问题讨论】:

如果您签署了该程序,我不希望您需要任何特定的“执行为”子句。您在上一段中提到了它,但是您是否尝试过创建一个角色,将您的基于证书的用户放入其中,并授予连接并授予该角色?我认为是的,但我也希望它能够工作...... @BenThul 也许帖子不够清楚,但是是的,这正是我正在做的。证书在初始数据库中制作,并复制到目标数据库,从中创建用户。用户被添加到Certified角色,该角色具有执行过程的权限,并且应该对整个目标数据库具有CONNECT WITH GRANT OPTION权限。 【参考方案1】:

我已经为我的案例解决了这个问题。要找到解决方案,请跳到水平换行符处。

如果我的原始帖子做得不好,为了澄清我的设置,我有一个数据库Initial,它创建了一个证书cCompCompID,用于在同一个数据库中签署一个过程。然后将证书复制到另一个数据库Target,用于创建用户uCompCompID,然后将其添加到角色Certified。该角色被授予执行ModifyUserCONNECT WITH GRANT OPTION 的权限,因此ModifyUser 可用于更改其他用户的连接权限,但仅当从Initial 中的签名过程调用时(这是一个模块签名的属性,我用它来尽可能保证系统的安全,防止意外访问这些过程)。

我想保留角色Certified 的权限而不是用户的权限,因为我知道我将来需要修改程序,这将需要退出Initial 中的程序,并且我需要创建一个新证书来签署该过程,然后将新证书复制到Target 数据库,删除并重新创建用户,然后我需要担心再次授予正确的权限。保留角色的权限可以简化流程。证书需要重新创建,因为在我所见的任何地方,推荐的做法是一旦使用完成就不要从证书中删除私钥,以防止以后意外使用它们。


授予角色具有GRANT OPTION 的权限的正确方法是在授予语句的末尾使用AS <role name>。 documentation on granting permissions on a database with an AS clause 解释了在我的原始帖子中的情况 2 中无法正常工作的原因。在授予、撤销或拒绝作为数据库角色的权限时,执行语句的用户必须:

角色的 ALTER 权限、db_securityadmin 固定数据库角色的成员资格、db_owner 固定数据库角色的成员资格或 sysadmin 固定服务器角色的成员资格。

我的问题的解决方案是授予证书用户 uCompCompID ALTER 对 Certified 角色的权限,以便它能够使用其角色成员身份授予或撤销权限。授予用户此权限不会造成安全威胁,因为ModifyUser 仅在从Initial 中的过程调用时授予uCompCompID 授予的权限,该过程由创建uCompCompID 的同一证书签名从。如果直接调用它,或者通过任何未由该证书签名的程序调用它,它将不具有这些权限,这要归功于模块签名(并且由于一旦对 Initial 中的程序进行签名,私钥就会从证书中删除,因此没有它被签署到其他任何东西以产生安全威胁而其他地方没有更大漏洞的风险)

正如@sepupic 指出的那样,我还需要使用相同的证书签署ModifyUser 才能获得工作权限。 ModifyUser 最初具有其权限,因为它是从使用证书签名的不同过程调用的。当ModifyUser在没有签名的情况下执行动态SQL时,这些额外的权限会被移除,直到动态SQL完成。如果ModifyUser使用相同的证书签名,那么ModifyUser执行的动态SQL将保留预期和需要的权限。

感谢@BenThul 和@sepupic 的帮助。

【讨论】:

【参考方案2】:

首先,您应该更新您的问题,因为不清楚您在哪些数据库中创建了 cerificate 以及哪个过程已签名,哪个未签名:

目标数据库中的过程(ModifyUser)被调用 初始数据库中的另一个过程 证书,其中有来自同一证书的用户 目标数据库是角色 Certified 的成员 授予 CONNECT WITH GRANT OPTION

由此看来,只有初始数据库中的过程是用 certificate,但内部过程(在目标数据库中)不是,在这种情况下,只有外部过程具有授予从证书创建的用户的权限,这就是您收到错误 N3 的原因

Grantor 没有 GRANT 权限

在其他情况下,您会因为使用execute as 子句而收到错误(该子句只承认user,而不承认login!)。当您使用它时,您的 proc 被沙箱化在创建过程的database 中,即即使您是sysadmin,您也不能在另一个数据库中执行任何操作,服务器不能使用相应的login(搜索相应的user 在其他数据库中)除非数据库是 trustworthy 并且 owner 在另一个数据库中没有 authenticate

【讨论】:

第二个过程不需要用证书签名,否则我一开始就无法运行它。证书是在初始数据库中创建的,并复制到目标数据库,在目标数据库中,从证书创建用户并添加到有权执行第二个过程的角色,并且应该有权授予/撤销 CONNECT 权限.关于不用于撤销/拒绝权限的模块签名,据我了解,它指的是证书用户的权限,而不是像我正在做的那样通过动态 SQL。 内部过程也必须签名。你可以在这个博客中找到它:sommarskog.se/grantperm.html 如果你也想在内部过程中获得证书的权力,你也需要签名。如果你仍然坚持,我可以用完整的重现来更新我的答案 我曾尝试签署内部程序以尝试更早地修复它,但它似乎没有解决问题(因为我仍然缺少 ALTER 权限和“AS Certified”的使用),所以最初我认为这没有必要,但是在进行了一些需要再次退出所有内容的更改之后(在开发过程中必须喜欢那个方面),似乎需要签名ModifyUser,以便它里面的动态SQL也有必要的权限。我的大多数程序都没有嵌套那么深,所以这对我来说是一个新问题。感谢您的链接。 >>> 似乎需要对 ModifyUser 进行签名,以便其中的动态 SQL 也具有必要的权限 关于授予AS:我没有分析这方面,我只评论了你的3个错误,每种情况的原因是什么

以上是关于如何授予用户角色具有授予选项的权限?的主要内容,如果未能解决你的问题,请参考以下文章

授予者没有 GRANT 权限 - 问题

未为角色“my_role_1”授予 ADMIN 选项

如何使用 LDAP 和基于角色的数据库授予权限来实现 Spring Security?

第四十八章 SQL命令 GRANT(二)

如何向 sql server 用户授予 sendmail 权限?

如何查看某个角色被授予的权限