如何对拥有VIEW ANY DATABASE权限的登录者隐藏指定SQL Server数据库
解决方案
一、优先隐藏目标数据库(推荐)
如果用户的VIEW ANY DATABASE权限来自默认的public服务器角色,可通过在目标数据库上拒绝两项核心权限,让所有非特权用户无法看到该数据库:
USE [目标数据库名]; GO -- 拒绝public角色查看数据库定义 DENY VIEW DEFINITION ON DATABASE::[目标数据库名] TO public; -- 拒绝public角色查看数据库状态 DENY VIEW DATABASE STATE ON DATABASE::[目标数据库名] TO public; GO
执行后,所有属于public角色且无更高权限(如sysadmin、db_owner)的登录用户,无论是在对象资源管理器还是执行SELECT name FROM sys.databases,都无法看到该数据库,且完全不影响他们对其他数据库的访问。
注意事项
- 若部分用户单独拥有服务器级的
VIEW DEFINITION权限(优先级高于数据库级拒绝),需单独针对这些用户执行拒绝操作。
二、批量限制数据访问(隐藏不可行时)
如果无法完全隐藏数据库,可通过自定义数据库角色批量配置拒绝权限,避免逐个指定用户:
- 创建自定义拒绝角色
USE [目标数据库名]; GO CREATE ROLE db_deny_restricted_access; -- 拒绝角色对数据库的所有SELECT权限 DENY SELECT ON DATABASE::[目标数据库名] TO db_deny_restricted_access; -- 可选:同时拒绝查看数据库内对象的定义 DENY VIEW DEFINITION ON DATABASE::[目标数据库名] TO db_deny_restricted_access; GO
- 批量添加符合条件的用户到角色
通过动态SQL,自动将所有拥有VIEW ANY DATABASE权限的登录对应的数据库用户(已存在的)添加到该角色:
USE [目标数据库名]; GO DECLARE @sql NVARCHAR(MAX) = N''; SELECT @sql += N' ALTER ROLE db_deny_restricted_access ADD MEMBER [' + dp.name + N'];' FROM sys.database_principals dp JOIN sys.server_principals sp ON dp.sid = sp.sid WHERE sp.type IN ('S', 'U', 'G') -- 覆盖SQL登录、Windows登录、Windows组 AND EXISTS ( SELECT 1 FROM sys.server_permissions spm WHERE spm.grantee_principal_id = sp.principal_id AND spm.permission_name = 'VIEW ANY DATABASE' AND spm.state IN ('G', 'W') -- 筛选已授予或带授予权限的用户 ); EXEC sp_executesql @sql; GO
补充:处理未映射的登录
如果有部分登录尚未在目标数据库中创建用户,可先批量创建用户再添加到角色:
USE [目标数据库名]; GO DECLARE @createSql NVARCHAR(MAX) = N'', @addRoleSql NVARCHAR(MAX) = N''; SELECT @createSql += N'CREATE USER [' + sp.name + N'] FOR LOGIN [' + sp.name + N'];', @addRoleSql += N'ALTER ROLE db_deny_restricted_access ADD MEMBER [' + sp.name + N'];' FROM sys.server_principals sp WHERE sp.type IN ('S', 'U', 'G') AND EXISTS ( SELECT 1 FROM sys.server_permissions spm WHERE spm.grantee_principal_id = sp.principal_id AND spm.permission_name = 'VIEW ANY DATABASE' AND spm.state IN ('G', 'W') ) AND NOT EXISTS ( SELECT 1 FROM sys.database_principals dp WHERE dp.sid = sp.sid ); EXEC sp_executesql @createSql; EXEC sp_executesql @addRoleSql; GO
三、权限验证
操作完成后,切换到目标登录账号,执行以下语句验证效果:
-- 检查是否能看到目标数据库 SELECT name FROM sys.databases WHERE name = '目标数据库名'; -- 检查是否能读取表数据 SELECT * FROM [目标数据库名].[dbo].[目标表名];
内容的提问来源于stack exchange,提问作者TK Bruin
相关产品推荐
相关产品推荐

