拒绝访问 SQL Server 中的信息架构

Swi*_*der 14 sql-server-2005 sql-server-2008 sql-server sql-server-2008-r2 information-schema

我正在寻找禁用SQL Server 中用户/组访问sys.tables/的最佳方法Information Schema

从 2008 年发现了这个线程

它显示了一种如何拒绝访问的方法,[sys].[something]如下所示:

 DENY SELECT ON [sys].[columns] TO DenySystemTableSelectRole
 GO
 DENY SELECT ON [sys].[tables] TO DenySystemTableSelectRole
 GO
 DENY SELECT ON [sys].[syscolumns] TO DenySystemTableSelectRole
 GO
 DENY SELECT ON [sys].[sysobjects] TO DenySystemTableSelectRole
 GO
Run Code Online (Sandbox Code Playgroud)

但是没有办法如何禁用对以下内容的访问Information Schema

DENY SELECT ON INFORMATION_SCHEMA.TABLES To DenySystemTableSelectRole
Run Code Online (Sandbox Code Playgroud)

这似乎不起作用。

如何禁用对 information_schema 的访问?

是否有更简单的方法禁用对所有sys/ 的访问information_schema

更新: 实际上我不能同时运行以下语句:

DENY SELECT ON [sys] TO reducedDBO
GO
DENY SELECT ON INFORMATION_SCHEMA To reducedDBO
GO
Run Code Online (Sandbox Code Playgroud)

我尝试在用户所在的特定数据库上运行它们,我也尝试在“master”上运行。

我仍然可以运行:

 SELECT * from
 INFORMATION_SCHEMA.TABLES 
Run Code Online (Sandbox Code Playgroud)

--> 仍然返回结果

 SELECT * from
 sys.TABLES 
Run Code Online (Sandbox Code Playgroud)

--> 没有结果了

包括SCHEMA::在查询中可以创建安全对象

DENY SELECT ON SCHEMA::[sys] TO reducedDBO
GO
DENY SELECT ON SCHEMA::INFORMATION_SCHEMA To reducedDBO
GO
Run Code Online (Sandbox Code Playgroud)

但是现在我仍然可以从数据库中选择所有信息。

我查看了 Management Studio 2008 中用户属性窗口中的“Securables”-Tab,它看起来像这样:

阻止选择 sys.tables 的条目

架构:系统,名称:表,类型:视图

sys.tables 的权限: Permission:Select, Grantor:dbo, Deny 被选中

不阻止任何选择的条目

架构:,名称:INFORMATION_SCHEMA,类型:架构

INFORMATION_SCHEMA 的权限:Permission:Select、Grantor:dbo、Deny 没有被检查(我试图检查它,但没有机会......)

权限:选择,授予者:INFORMATION_SCHEMA,拒绝被选中


我试图通过 GUI 设置权限,但随后我得到了同样的错误,即只能在主数据库上设置权限。但是我没有将用户/登录名添加到主数据库安全性中。

解决方案:

我可以为deny工作的唯一方法information_schema将用户添加到主数据库在主数据库上运行deny select

DENY SELECT ON [sys].[tables] TO reducedDBO
GO
DENY SELECT ON INFORMATION_SCHEMA.TABLES To reducedDBO
GO
Run Code Online (Sandbox Code Playgroud)

并且在这段代码中,它只能对单个表执行。

mar*_*c_s 11

你应该能够只是否认对整个权限sysinformation_schema架构作为一个整体:

DENY SELECT On SCHEMA::sys To [user_name]
DENY SELECT On SCHEMA::INFORMATION_SCHEMA To [user_name]
Run Code Online (Sandbox Code Playgroud)

这基本上应该只是阻止该用户在这两个模式中进行任何选择。


小智 6

首先,您是正确的,防止访问 [sys] 和 [INFORMATION_SCHEMA] 模式的(稍微违反直觉的)方法是首先确保登录(好吧,服务器级主体)作为用户(erm,数据库级主体)在 master 数据库中。

为简单起见,假设您有一个 SQL 登录名:

CREATE LOGIN [testy] WITH PASSWORD=N'SCoBIqlJELGzrY9zYsKWC5z3kHtMsyCAP6yBHLUYQ0w='
go
Run Code Online (Sandbox Code Playgroud)

现在在master数据库中创建一个对应的用户:

use [master]
go
CREATE USER [testy] FOR LOGIN [testy]
go
Run Code Online (Sandbox Code Playgroud)

现在您想阻止此登录访问系统提供的架构中的任何表 - [sys] 和 [INFORMATION_SCHEMA]。

SQL Server 2008 R2 和 SQL Server 2012 之间的行为似乎发生了变化:

在 SQL Server 2012(以及可能的更高版本)中,在 [master] 数据库中运行以下内容与您预期的一样:

DENY SELECT, VIEW DEFINITION ON SCHEMA::[sys] to [testy];
GO
DENY SELECT, VIEW DEFINITION ON SCHEMA::[INFORMATION_SCHEMA] to [testy];
GO
Run Code Online (Sandbox Code Playgroud)

但是,在 SQL Server 2008 R2(以及可能更早的版本)中,向 [public] 成员提供对这些架构中对象的访问权限的股票授权语句似乎覆盖了上述 DENY 语句,这对我来说似乎是一大堆失败。因此,在 2008 R2 上,您需要明确拒绝对 [public] 的每个 GRANT。这是一个脚本来做到这一点:

declare
    @database_principal sysname,
    @cur cursor,
    @sql nvarchar( 4000 );

set @database_principal = 'testy';

set @cur = cursor local forward_only static for
    select 
        'DENY ' +
        permission_name + ' on ' +
        case class 
            when 1 then
                case minor_id
                    when 0 then 'OBJECT'
                    else 'COLUMN'
                end
            else
                class_desc
        end + '::' +
        case class
            when 0 then db_name()
            when 1 then quotename( OBJECT_SCHEMA_NAME(major_id) ) + '.' + quotename( object_name( major_id ) ) + case minor_id when 0 then '' else ( select '.' + quotename( name ) collate database_default from sys.columns where column_id=minor_id) end
            when 3 then schema_name( major_id )
        end + ' to ' +
        quotename( @database_principal )
    from
        sys.database_permissions
    where
        [grantee_principal_id] = 0 -- public
        and
        [state_desc] = 'GRANT'
        and
        [permission_name] = 'SELECT'
;

open @cur;

while
    1 = 1
begin
    fetch @cur into @sql;
    if @@fetch_status <> 0 break;

    print @sql;
    exec sys.sp_executesql @sql;
end;

close @cur;

deallocate @cur;
Run Code Online (Sandbox Code Playgroud)

在 master 数据库中运行上面的内容,您已经删除了对这些模式内容的访问权限。

笔记:

  1. 因为这些是显式的 DENY 语句,所以它们在脚本运行时是正确的。如果有人随后更改了授予 public 的权限(例如,一个服务包创建了一个新的系统表),那么这将暴露给被拒绝的用户
  2. 使用数据库角色作为 DENY 语句的目标并将被拒绝的用户置于该角色中是一个好主意。
  3. 您可以通过将 DENY 更改为 REVOKE 来撤消此操作
  4. 如果在上面的脚本中注释掉以下两行:

        and
        [permission_name] = 'SELECT'
    
    Run Code Online (Sandbox Code Playgroud)

    它将具有撤消所有公共默认 GRANT的效果。这将阻止对例如 sys.sp_tables 的访问,从而破坏例如 Microsoft Access 的枚举表的能力,但在高安全性场景中这样做很有用,因此用户只能在您明确授予的地方获得访问权限它。