6

如何将db_owner固定数据库角色的所有权限和特权授予应用程序角色?

精简版

命令:

GRANT CONTROL ON [DatabaseName] TO [ApplicationRoleName];

将是我想要的,但它失败了:

消息 15151,级别 16,状态 1,第 23 行
找不到对象“数据库名称”,因为它不存在或您没有权限。

研究工作

我正在调查使用 SQL Server Application Roles

  • 它就像一个用户(因为它有一个用户名和密码)
  • 就像一个角色

一旦连接到服务器,您的应用程序就会运行一个存储过程来“登录”自己作为应用程序:

EXECUTE sp_SetAppRole @rolename = 'Contoso.exe', @password =
'Tm8gaSBkaWRuJ3QganVzdCBiYXNlNjQgZW5jb2RlIGEgcGFzc3dvcmQuIEl0J3Mgb25seSBhbiBleGFtcGxlIQ==';

db_owner 的权限

通常,应用程序作为db_owner固定角色成员的用户登录。该角色具有以下权限:db_owner

  • 对一切
  • 在每张桌子上
  • 每个视图
  • 每个存储过程、函数
  • 对于所有现有对象
  • 以及未来将存在的所有对象

同时:

  • 您可以将用户放入数据库角色
  • 您可以将用户置于应用程序角色中

您不能将应用程序角色放入数据库角色

那么,接下来的问题是:如何授予我的应用程序角色所有权限(即做所有事情)?

角色的权限

所以,现在是授予角色权限的时候了。按照此页面的建议

GRANT SELECT, INSERT, UPDATE, DELETE ON Users TO [Contoso.exe];

这很有趣,但它并没有授予所有特权——它只授予SELECTINSERTUPDATEDELETE. 我想授予一切——尤其是当我不知道所有特权是(或可能是)什么时。

我盲目地尝试:

GRANT ALL ON Users to [Contoso.exe];

以下出现在“消息”选项卡中:

ALL 权限已被弃用,仅为了兼容性而维护。它并不意味着在实体上定义的所有权限。

好的,所以授予ALL并不授予所有。这……太可怕了。

所以我回到:

GRANT SELECT, INSERT, UPDATE, DELETE ON Users TO [Contoso.exe];

除了这并不能授予一切。例如,我碰巧知道有能力继续授予他人特权(具有的特权db_owner)。所以我必须将我的声明更改为:

GRANT SELECT, INSERT, UPDATE, DELETE ON Users TO [Contoso.exe] WITH GRANT OPTION;

好的,这样更接近了,但它只适用于一张桌子。

我需要适用于所有表格的东西:

EXECUTE sp_msForEachTable 'GRANT SELECT, INSERT, UPDATE, DELETE ON ? TO [Contoso.exe] WITH GRANT OPTION;';

虽然,事实证明我错过了一些特权:

  • 选择✔️
  • 插入✔️
  • 更新✔️
  • 删除✔️
  • 参考文献❌</li>
  • 改变❌</li>

当然,我可以更新我的脚本:

EXECUTE sp_msForEachTable 'GRANT SELECT, INSERT, UPDATE, DELETE, REFERENCES, ALTER ON ? TO [Contoso.exe] WITH GRANT OPTION;';

但是,而不是这个猫捉老鼠的猜谜游戏:我想授予所有权限。

几乎所有

在上面的警告中,SQL Server 指出ALL并不授予所有权限。但他们确实记录了所有授予的内容:

| Permission | Table | View | SP | Scalar UDF | Table UDF |
|------------|-------|------|----|------------|-----------|
| SELECT     |  ✔️   |  ✔️ |    |            |     ✔️    |
| INSERT     |  ✔️   |  ✔️ |    |            |     ✔️    |
| UPDATE     |  ✔️   |  ✔️ |    |            |     ✔️    |
| DELETE     |  ✔️   |  ✔️ |    |            |     ✔️    |
| REFERENCES |  ✔️   |  ✔️ |    |    ✔️      |     ✔️    |
| EXECUTE    |       |      | ✔️ |    ✔️     |            |
| ALTER      |  ❌   |  ❌ | ❌ |    ❌     |      ❌   | 

控制所有权限

原来他们都被骗了。为创建另一个权限。一项统治他们的权限

  • 控制

授予受让人类似所有权的能力。被授权者实际上拥有对安全对象的所有已定义权限。已被授予 CONTROL 的主体也可以授予对安全对象的权限。由于 SQL Server 安全模型是分层的,因此特定范围内的 CONTROL 隐式包含对该范围内所有安全对象的 CONTROL。例如,对数据库的 CONTROL 意味着对数据库的所有权限、对数据库中所有程序集的所有权限、对数据库中所有架构的所有权限以及对数据库内所有架构内对象的所有权限。

他们继续枚举当您拥有CONTROL时隐含的权限:

  • 改变
  • 控制
  • 删除
  • 执行
  • 插入
  • 收到
  • 参考
  • 控制
  • 取得所有权
  • 更新
  • 查看更改跟踪
  • 查看定义

那好多了。而不必知道所有的权限,我只授予一个。我不知道哪些权限适用于哪些类型的对象,我只授予一个。因为这条线:

已被授予 CONTROL 的主体也可以授予对安全对象的权限。

我不必GRANT WITH GRANT

-- when you have CONTROL you also get WITH GRANT for free
EXECUTE sp_msForEachTable 'GRANT CONTROL ON ? TO [Contoso.exe];';

对所有对象

我的问题是我需要为数据库中的每个对象授予 CONTROL 权限。并且无论何时添加任何新对象,我都必须确保返回并将其添加到应用程序角色中。

我需要的是微软暗示的东西:

例如,对数据库的 CONTROL 意味着对数据库的所有权限、对数据库中所有程序集的所有权限、对数据库中所有架构的所有权限以及对数据库内所有架构内对象的所有权限。

CONTROL重申一下,如果您授予数据库,那么您将拥有所有权限:

  • 在数据库上
    • 所有对象
    • 数据库中的所有程序集
    • 所有模式

就是我想要的。我想将数据库GRANT CONTROL权限授予应用程序角色:Grobber[Contoso.exe]

GRANT CONTROL ON Grobber TO [Contoso.exe];

Msg 15151, Level 16, State 1, Line 23
Cannot find the object 'Grobber ', because it does not exist or you do not have permission.

我可能几乎解决了我的问题,只是停在 1 码线。

或者,我可能不在附近。所以我问:

如何将 db_owner 权限授予另一个角色?

编辑:警告:不要使用应用程序角色 - 它会破坏一切

当您的客户端登录到应用程序角色时,该身份是该连接的持久属性。并且使用连接池(在 ADO.net、ADO 和 ODBC 中是首选和默认选项),即使在您关闭连接之后,连接也会长时间保持打开状态。

当您的应用程序(即网络服务器)尝试打开一个新连接时,它会从连接池中获取一个。SqlConnection所做的第一件事是尝试将连接状态重置为默认值(使用sp_reset_connection)。

尝试做的一件事是撤销您是应用角色用户sp_reset_connection的事实。这是不允许的(因为服务器不知道你以前是谁)。因此,通过使用应用程序角色,当您尝试连接到服务器时会突然出错。

“修复”它的唯一方法是禁用连接池。

这是你不想做的事情。

因此解决方案是不在生产环境中使用应用程序角色。

4

2 回答 2

6

“您不能将应用程序角色放入数据库角色”似乎是不正确的部分。可以将(应用程序)角色添加为另一个角色的成员:

EXEC sp_addrolemember 'db_owner', 'ApplicationRoleName';

(从 2012 年开始,此过程已被弃用,取而代之的是新ALTER ROLE .. ADD MEMBER语法。)

GRANT CONTROL对整个数据库赋予一个角色,以下将执行以下操作:

USE [DatabaseName];
GRANT CONTROL ON DATABASE::[DatabaseName] TO [ApplicationRoleName];

USE对于将角色纳入范​​围是必要的;引用数据库时,DATABASE::范围限定符始终是必需的。

说了这么多,应用程序角色可能不是授予最广泛权限的好人选。它的密码以明文形式传递,除非注意加密连接本身,监控和审计可能会忽略它,并且在不再需要权限时很容易忘记恢复。最后一部分更加隐蔽,因为未恢复的应用角色激活将在池连接中持续存在,从而使连接“卡住”在管理模式下。替代方法包括使用新凭据打开单独的连接以执行任意操作,以及使用存储过程来EXECUTE AS获取无法GRANT有效编辑的权限。

于 2019-02-05T15:24:13.037 回答
1

尝试做的一件事是撤销您是应用角色用户sp_reset_connection的事实。这是不允许的(因为服务器不知道你以前是谁)。 ... “修复”它的唯一方法是禁用连接池。

撤消应用角色不能由 自动完成sp_reset_connection,但可以完成(从 SQL Server 2005 开始)。它只需要通过sp_unsetapprole手动完成。这需要指示sp_setapprole生成 cookie(VARBINARY值),在执行该系统过程时捕获它,并将其存储在某处(通过CONTEXT_INFO或更新的 SQL Server 中SESSION_CONTEXT,或在应用程序层中)。然后,您只需要在关闭sp_unsetapprole 之前SqlConnection将该值传递回(即将该连接返回到池)。

从理论上讲,使用EXECUTE AS切换安全上下文可能是sp_reset_connection可以撤消的,因为它只需要REVERT在 T-SQL 中执行(不需要 cookie 值),并且如果没有要恢复REVERT的上下文切换不会出错(只有在在活动数据库与EXECUTE AS执行时不同时调用)。但是,我没有时间对此进行测试(无论如何这不是推荐的做法)。

通常,应用程序以作为固定角色成员的用户身份登录。db_owner

现在这肯定不理想(特别是如果拥有数据库的登录名具有任何管理员权限)。是的,它确实使某些任务更容易,因为您有效地禁用了所有安全性,因此您永远不会收到权限错误,但这种方法非常不安全,即使您确实添加了设置应用程序角色所需的密码的额外步骤。

首选方法(非常细化且非常安全)是使用Module Signing。通过签署您的模块(存储过程、标量函数、多语句 TVF 和触发器),您可以为它们(模块)授予执行封装代码所需的任何权限,而不必担心任何人获得这些权限并做某事无意与他们在一起。在这种方法中,您授予代码权限,而不是用户(即人员/应用程序登录)。我有更多关于您为什么要从应用程序角色和EXECUTE AS切换到模块签名的详细信息:请,请,请停止使用模拟、可信和跨数据库所有权链接。具体示例见:

于 2019-12-13T18:34:00.547 回答