查看和 table 安全冲突解决方案

View and table security conflict resolution

我有一个 SQL Server 2017 实例,上面有 5 个数据库。 A、B、C、D、E。数据库 A 只包含模式和视图。实例上的每个后续数据库(A、B、C、D、E)都有一个模式,每个模式拥有 50 - 150 个视图。

我需要能够授予用户 select 对数据库 A 中所有视图的权限,但直接拒绝对所有 table 的 select 权限。

测试条件应该是这样的。

SELECT * FROM [B].dbo.[any_table] (DENIED)
SELECT * FROM [A].[B].some_view (WORKS)

由于架构 A - E 都归 dbo 所有,我假设我可以执行以下操作:

USE A
GO

CREATE ROLE db_viewreader
GO

GRANT SELECT ON SCHEMA::A TO db_viewreader (repeat for b, c, d, e)
GO

CREATE USER testuser WITHOUT LOGIN
GO
ALTER ROLE db_viewreader ADD MEMBER testuser
GO

EXECUTE AS USER = 'testuser'

SELECT *
FROM [A].[B].some_view

我无法从视图或 table 中获得结果。我想我明白为什么我没有得到查询 tables 的结果,因为我创建的用户在数据库 B-E 中不存在。这是否与我无法调用访问底层数据的视图的原因相同 tables?如果是这样,我有什么办法可以创建一个可以使用视图但不能使用它们位于其上的 tables 的用户?

可以允许 SELECT 访问视图而无需使用 ownership chaining 访问基础 table 的视图。只要所涉及的所有对象都属于同一安全主体,所有权链接将允许授予视图权限的用户使用它,而不管视图引用的 tables 的权限如何。

对不同数据库中的对象使用所有权链还有其他注意事项。

  • 必须为涉及的数据库打开DB_CHAINING选项 或打开服务器级 cross db ownership chaining 选项:

    ALTER DATABASE A SET DB_CHAINING ON;
    ALTER DATABASE B SET DB_CHAINING ON;
    ALTER DATABASE C SET DB_CHAINING ON;
    ALTER DATABASE D SET DB_CHAINING ON;
    ALTER DATABASE E SET DB_CHAINING ON;
    
  • 用户必须是服务器级别的主体并添加到每个数据库(或在其他数据库中启用的来宾用户):

    CREATE LOGIN testuser WITH PASSWORD = 'n3$(s(+#BB4--';
    USE A;CREATE USER testuser;ALTER ROLE db_viewreader ADD MEMBER testuser;
    USE B;CREATE USER testuser;
    USE C;CREATE USER testuser;
    USE D;CREATE USER testuser;
    USE E;CREATE USER testuser;
    
  • 对象所有者,通常继承自对象的架构 AUTHORIZATION,所有涉及的对象必须是相同的安全主体。对于 dbo 用户,这是数据库所有者登录名:

    ALTER AUTHORIZATION ON DATABASE::A TO DatabaseOwnerLogin;
    ALTER AUTHORIZATION ON DATABASE::B TO DatabaseOwnerLogin;
    ALTER AUTHORIZATION ON DATABASE::C TO DatabaseOwnerLogin;
    ALTER AUTHORIZATION ON DATABASE::D TO DatabaseOwnerLogin;
    ALTER AUTHORIZATION ON DATABASE::E TO DatabaseOwnerLogin;
    

请注意,在 table 上不需要明确的 DENY,除非您已直接或通过角色成员身份授予用户对 table 的权限。除非授予,否则用户默认没有对象权限。

要测试权限,您需要模拟服务器级别主体而不是数据库用户,否则 db 用户将在上下文数据库中被沙盒化(除非数据库是 TRUSTWORTHY):

USE A;
GO
EXECUTE AS LOGIN = 'testuser';
GO
SELECT *
FROM [A].[B].some_view;
GO
REVERT;
GO

请注意,由于以下文档摘录中所述的原因,跨数据库的所有权链接在默认情况下处于关闭状态。当只有 sysadmin 角色成员可以在生产数据库中创建数据库对象时,这可能不是一个问题,当然,在部署之前检查代码。

Database owners and members of the db_ddladmin or the db_owners database roles can create objects that are owned by other users. These objects can potentially target objects in other databases. This means that if you enable cross-database ownership chaining, you must fully trust these users with data in all databases.