防止 SSMS 看到服务器的文件系统

fin*_*nal 11 sql-server ssms sql-server-2017

我有几个用户在我的管理下共享 MS SQL Server 2017。他们不应该看到(甚至不知道)该服务器上的其他用户及其数据。每个用户都有自己的数据库。他们可以对他们的数据库做任何他们想做的事情。

我正在使用 SQL Server 的Partial Containment功能将用户锁定到位。登录名是在数据库中创建的。这很有效,因为他们不会以这种方式看到其他用户帐户或数据库。数据库登录名被添加到我使用以下命令创建的数据库角色中:

USE dbname
CREATE ROLE dbrole
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, CREATE VIEW, ALTER ANY SCHEMA TO dbrole
DENY EXECUTE TO dbrole
Run Code Online (Sandbox Code Playgroud)

我刚刚创建了一个 db 登录帐户,并将其添加到所述角色中。用户没有其他权限(我知道)。

剩下的唯一问题是 SSMS 仍然能够浏览服务器的文件系统。如果我右键单击数据库并选择Tasks -> Restore -> Database,然后选择Device: -> [...]并添加文件。这允许 SSMS 浏览服务器的文件系统,我想否认这一点。用户实际上不能恢复数据库,但他可以浏览文件系统。

这里的这个问题表明 SSMS 正在使用存储过程xp_fixeddrivesxp_dirtree并且xp_fileexist. 但是,当以具有该组权限的用户身份执行时,这些存储过程返回空结果。我读过这是当用户不是 sysadmin 角色的成员时的行为。这已经让我有点困惑,因为我明确拒绝对 dbrole 执行 EXECUTE,但用户仍然可以执行存储过程。但是,通过 SSMS 浏览文件系统时,它仍然不是空的。

SSMS 从哪里获取文件系统信息,如何防止这种情况发生?

编辑:我也刚刚注意到 SSMS 能够检索所有数据库的服务器上存在的所有数据库备份的列表。同样,我不知道它如何获取这些信息以及如何防止它。

Ran*_*gen 10

跟踪查询

在跟踪执行的查询时,发现下面的查询将驱动器上的文件夹一一列出。

declare @Path nvarchar(255)
declare @Name nvarchar(255)


select @Path = N'D:\'


select @Name = null;


        create table #filetmpfin (Name nvarchar(255) NOT NULL, IsFile bit NULL, FullName nvarchar(300) not NULL)
        declare @FullName nvarchar(300)  
        if exists (select 1 from sys.all_objects where name = 'dm_os_enumerate_filesystem' and type = 'IF' and is_ms_shipped = 1)
        begin 
          if (@Name is null)
          begin 
              insert #filetmpfin select file_or_directory_name, 1 - is_directory, full_filesystem_path from sys.dm_os_enumerate_filesystem(@Path, '*') where [level] = 0
          end 
          if (NOT @Name is null)
          begin 
            if(@Path is null) 
              select @FullName = @Name 
            else
              select @FullName = @Path  + convert(nvarchar(1), serverproperty('PathSeparator')) + @Name 
              create table #filetmp3 ( Exist bit NOT NULL, IsDir bit NOT NULL, DirExist bit NULL ) 
              insert #filetmp3 select file_exists, file_is_a_directory, parent_directory_exists from sys.dm_os_file_exists(@FullName) 
              insert #filetmpfin select @Name, 1-IsDir, @FullName from #filetmp3 where Exist = 1 or IsDir = 1 
              drop table #filetmp3 
          end
        end 
        else      
        begin         
          if(@Name is null)
          begin
            if (right(@Path, 1) = '\')
              select @Path= substring(@Path, 1, len(@Path) - charindex('\', reverse(@Path)))
            create table #filetmp (Name nvarchar(255) NOT NULL, depth int NOT NULL, IsFile bit NULL )
            insert #filetmp EXECUTE master.dbo.xp_dirtree @Path, 1, 1
            insert #filetmpfin select Name, IsFile, @Path + '\' + Name from #filetmp f
            drop table #filetmp
          end 
          if(NOT @Name is null)
          begin
            if(@Path is null)
              select @FullName = @Name
            else
              select @FullName = @Path +  '\' + @Name
            if (right(@FullName, 1) = '\')
              select @Path= substring(@Path, 1, len(@FullName) - charindex('\', reverse(@FullName)))
            create table #filetmp2 ( Exist bit NOT NULL, IsDir bit NOT NULL, DirExist bit NULL )
            insert #filetmp2 EXECUTE master.dbo.xp_fileexist @FullName
            insert #filetmpfin select @Name, 1-IsDir, @FullName from #filetmp2 where Exist = 1 or IsDir = 1 
            drop table #filetmp2
          end 
        end 



SELECT
Name AS [Name],
IsFile AS [IsFile],
FullName AS [FullName]
FROM
#filetmpfin
ORDER BY
[IsFile] ASC,[Name] ASC
drop table #filetmpfin
Run Code Online (Sandbox Code Playgroud)

使用的主要功能是sys.dm_os_enumerate_filesystem,对于打开的每个文件夹,它会更深一层,第二层的示例:

select @Path = N'D:\Data\'
Run Code Online (Sandbox Code Playgroud)

对于常规登录

对于常规登录,只需拒绝对此 TVF 的选择权限,即可让用户无法列出文件夹。

DENY SELECT ON master.sys.dm_os_enumerate_filesystem TO [Domain\LoginName]
Run Code Online (Sandbox Code Playgroud)

尝试选择备份时,用户应该看到以下消息:

在此处输入图片说明

然后用户将只能看到驱动器号。

在此处输入图片说明


对于包含的用户

对于被包含的用户,直接在TVF上拒绝select是不行的

包含的用户可以成功运行下一个查询示例

declare @Path nvarchar(255)
declare @Name nvarchar(255)


select @Path = N'D:\'
select file_or_directory_name, 1 - is_directory, full_filesystem_path from sys.dm_os_enumerate_filesystem(@Path, '*') where [level] = 0
Run Code Online (Sandbox Code Playgroud)

而且......这不起作用:

use [PartialDb]
GO
DENY SELECT ON [sys].[dm_os_enumerate_filesystem] TO [PartialUser];
GO
Run Code Online (Sandbox Code Playgroud)

消息 4629,级别 16,状态 10,第 34 行 只有当当前数据库是 master 时,才能授予对服务器范围目录视图或系统存储过程或扩展存储过程的权限。

下面的语句有效,但它们不会限制用户,即使它不是dbrole角色的一部分

DENY VIEW DATABASE STATE TO [PartialUser];

DENY VIEW DEFINITION ON SCHEMA :: information_schema TO [PartialUser];

DENY VIEW DEFINITION ON SCHEMA :: sys TO [PartialUser];

DENY SELECT ON SCHEMA :: information_schema TO [PartialUser];

DENY SELECT ON SCHEMA :: sys TO [PartialUser];
Run Code Online (Sandbox Code Playgroud)

有什么作用? 理论上

由于包含的用户使用来宾帐户/公共角色来连接并从 dmv 中进行选择,(公共角色默认可以访问某些对象)我们可以尝试限制公共角色。

由于多种原因,这并不理想。例如,拒绝 > 授予,因此只有sysadmin角色中的成员才能从此 TVF 中进行选择。

另一个需要注意的重要事项是,更改来宾用户/公共角色可能会对实例或某些功能产生未知的副作用。

USE MASTER
GO
DENY SELECT ON [sys].[dm_os_enumerate_filesystem] TO public;
GO
Run Code Online (Sandbox Code Playgroud)

更改公共/访客权限不是理想的方案。

例如,禁用来宾用户可能会破坏 msdb 数据库

在包含的用户的上下文中重新运行选择:

消息 229,级别 14,状态 5,第 7 行 对象“dm_os_enumerate_filesystem”、数据库“mssqlsystemresource”、架构“sys”的 SELECT 权限被拒绝。

这种远非理想的方法可能有也可能没有,我还没有找到。

公共角色的权限示例:

在此处输入图片说明

授予这些是有原因的,因为在拒绝/撤销这些对象时,某些功能可能会中断。谨慎行事。

关于访客用户/公共角色的更多信息在这里