元数据可见性配置

适用于:SQL Server (所有受支持的版本) Azure SQL数据库Azure SQL 托管实例 Azure Synapse Analytics Platform System (PDW)

元数据的可见性仅限用户所拥有的安全对象,或已授予用户某些权限的安全对象。 例如,如果用户获得了对表 myTable的 SELECT 或 INSERT 权限,则下面的查询将返回一行。

SELECT name, object_id  
FROM sys.tables  
WHERE name = N'myTable';  
GO  

但如果用户对 myTable没有任何权限,则查询返回空的结果集。

元数据可见性配置的作用域和影响

元数据可见性配置仅可应用于下列安全对象。

目录视图

公开元数据的内置函数

兼容性视图

数据库引擎 sp_help 存储过程

信息架构视图

扩展属性

元数据可见性配置不能应用于下列安全对象。

日志传送系统表

数据库维护计划系统表

复制系统表

SQL Server 代理系统表

备份系统表

复制及 SQL Server 代理 sp_help 存储过程

有限的元数据可访问性意味着:

  • 假定 public 可访问元数据的应用程序将中断。

  • 对系统视图的查询可能只返回行子集,有时返回空的结果集。

  • 元数据生成的内置函数(如 OBJECTPROPERTYEX)可能返回 NULL

  • 数据库引擎 sp_help 储过程可能只返回行子集或 NULL

SQL 模块(如存储过程和触发器)在调用方的安全上下文中运行,因此,它们只有有限的元数据访问性。 例如,在以下代码中,当存储过程尝试访问表 myTable (调用方对该表没有权限)的元数据时,返回空的结果集。 在早期版本的 SQL Server中,返回一行。

CREATE PROCEDURE assumes_caller_can_access_metadata  
BEGIN  
SELECT name, object_id   
FROM sys.objects   
WHERE name = N'myTable';  
END;  
GO  

若要允许调用方查看元数据,可在适当的作用域(对象级、数据库级或服务器级)中授予调用方 VIEW DEFINITION 权限。 因此,在以上示例中,如果调用方对 myTable具有 VIEW DEFINITION 权限,则存储过程返回一行。 有关详细信息,请参阅 GRANT (Transact-SQL) GRANT 数据库权限 (Transact-SQL)

也可以将存储过程修改为使用所有者凭据执行。 当过程所有者和表所有者相同时,便会应用所有权链,并且过程所有者的安全上下文便会启用对 myTable元数据的访问。 在这种情况下,以下代码会向调用方返回一行元数据。

注意

以下示例使用的是 sys.objects 目录视图,而非 sys.sysobjects 兼容视图。

CREATE PROCEDURE does_not_assume_caller_can_access_metadata  
WITH EXECUTE AS OWNER  
AS  
BEGIN  
SELECT name, object_id  
FROM sys.objects   
WHERE name = N'myTable'   
END;  
GO  

注意

您可以使用 EXECUTE AS 临时切换到调用方的安全上下文。 有关详细信息,请参阅 EXECUTE AS (Transact-SQL)

元数据可见性配置的优点和限制

元数据可见性配置在整个安全计划中发挥着重要作用。 但在有些情况下,有经验的用户和已确定的用户可以强制公开某些元数据。 建议将元数据权限部署为多种深层防御中的一种。

理论上可以通过控制查询中的谓词评估顺序,强制在错误消息中显示元数据。 此类“试错攻击”的威胁并非是 SQL Server 专有的。 它由关系代数中允许的关联转换和交换转换表示。 可以通过限制错误消息中返回的信息来降低此风险。 为了以此方式进一步限制元数据的可见性,可以使用跟踪标志 3625 启动服务器。 此跟踪标志限制错误消息中显示的信息量。 进一步有助于防止强制泄漏。 需要在错误消息的简洁性和用于调试的难易程度之间进行权衡。 有关详细信息,请参阅 数据库引擎服务启动选项跟踪标志 (Transact-SQL)

下列元数据无法强制公开:

  • 存储在 provider_stringsys.servers列中的值。 没有 ALTER ANY LINKED SERVER 权限的用户将看到此列中的值为 NULL

  • 用户定义的对象(如存储过程或触发器)的源定义。 只有在满足下列某一种条件时,才能看到源代码:

    • 用户对该对象具有 VIEW DEFINITION 权限。

    • 用户没有被拒绝对该对象具有 VIEW DEFINITION 权限,并且还对其具有 CONTROL、ALTER 或 TAKE OWNERSHIP 权限 。 所有其他用户看到的是 NULL

  • 在下列目录视图中找到的定义列:

    • sys.all_sql_modules
    • sys.server_sql_modules
    • sys.default_constraints
    • sys.numbered_procedures
    • sys.sql_modules
    • sys.check_constraints
    • sys.computed_columns
  • ctext 兼容视图中的 syscomments 列。

  • sp_helptext 过程的输出。

  • 信息架构视图中的以下列:

    • INFORMATION_SCHEMA.CHECK_CONSTRAINTS.CHECK_CLAUSE
    • INFORMATION_SCHEMA.DOMAINS.DOMAIN_DEFAULT
    • INFORMATION_SCHEMA.ROUTINES.ROUTINE_DEFINITION
    • INFORMATION_SCHEMA.COLUMNS.COLUMN_DEFAULT
    • INFORMATION_SCHEMA.ROUTINE_COLUMNS.COLUMN_DEFAULT
    • INFORMATION_SCHEMA.VIEWS.VIEW_DEFINITION
  • OBJECT_DEFINITION() 函数

  • 存储在 sys.sql_logins的 password_hash 列中的值。 不具有 CONTROL SERVER 权限的用户可以看到该列中的 NULL 值。

注意

内置系统过程和函数的 SQL 定义通过 sys.system_sql_modules 目录视图、 sp_helptext 存储过程以及 OBJECT_DEFINITION() 函数公开可见。

注意

Azure Synapse Analytics 不支持系统存储过程 sp_helptext。 而是改用 sys.sql_modules 对象目录视图。

元数据可见性的一般原则

下列是需要注意的有关元数据可见性的一般原则:

  • 固定角色隐式权限

  • 权限的作用域

  • DENY 的优先顺序

  • 子组件元数据的可见性

固定角色和隐式权限

固定角色可以访问的元数据取决于这些角色相应的隐式权限。

权限的作用域

某个作用域上的权限意味着可以查看该作用域和所有包含的作用域上的元数据。 例如,对架构的 SELECT 权限意味着被授权者对该架构所包含的所有安全对象都具有 SELECT 权限 。 因此,授予对架构的 SELECT 权限可以使用户查看架构的元数据以及其中的所有表、视图、函数、过程、队列、同义词、类型和 XML 架构集合。 有关范围的详细信息,请参阅 权限层次结构 (数据库引擎)

注意

UNMASK 权限不会影响元数据可见性:单纯授予 UNMASK 并不会泄露任何元数据 。 UNMASK 将始终需要伴有 SELECT 权限才能有效果 。 示例:在数据库范围内授予 UNMASK 并授予单个表的 SELECT,将导致用户只能看到单个表(可从中选择)的元数据,而看不到其他任何元数据 。

DENY 的优先顺序

DENY 通常优先于其他权限。 例如,如果授予数据库用户对架构的 EXECUTE 权限,但是拒绝其对架构中存储过程的 EXECUTE 权限,则该用户不能查看此存储过程的元数据 。

另外,如果拒绝用户对某个架构具有 EXECUTE 权限,但授予其对该架构中某个存储过程具有 EXECUTE 权限,则该用户无法查看该存储过程的元数据 。

再比如,如果通过各种角色成员身份同时授予和拒绝用户对存储过程的 EXECUTE 权限,则优先执行 DENY 权限,因此,用户不能查看存储过程的元数据 。

子组件元数据的可见性

索引、检查约束和触发器这类子组件的可见性由对父级组件的权限决定。 这些子组件没有可授予的权限。 例如,如果针对表授予用户某些权限,则用户可以查看表、列、索引、检查约束、触发器以及其他此类子组件的元数据。 另一个示例是只对给定表中的单个列授予 SELECT 权限:这将允许被授权者查看整个表的元数据(包括所有列)。 可以这样想,VIEW DEFINITION 权限只对实体级别(本例中的表)有效,而对子实体列表(如列或安全性表达式)无效。

下面的代码展示了这种行为:

CREATE TABLE t1
(
    c1 int,
    c2 varchar
 );
GO
CREATE USER testUser WITHOUT LOGIN;
GO

EXECUTE AS USER='testUser';
SELECT OBJECT_SCHEMA_NAME(object_id), OBJECT_NAME(object_id), name FROM sys.columns;
SELECT * FROM sys.tables
-- this returns no data, as the user has no permissions
REVERT;
GO

-- granting SELECT on only 1 column of the table:
GRANT SELECT ON t1(c1) TO testUser;
GO
EXECUTE AS USER='testUser';
SELECT OBJECT_SCHEMA_NAME(object_id), OBJECT_NAME(object_id), name FROM sys.columns;
SELECT * FROM sys.tables
-- this returns metadata for all columns of the table and thge table itself
REVERT;
GO

DROP TABLE t1
DROP USER testUser

所有数据库用户可访问的元数据

某些元数据对于特定数据库中的所有用户都必须是可访问的。 例如,文件组没有可授予的权限,因此不能授予用户查看文件组的元数据的权限。 但是,可以创建表的任何用户都必须能够访问文件组元数据,以使用 CREATE TABLE 语句的 ON filegroup 或 TEXTIMAGE_ON filegroup 子句。

所有用户均可查看由 DB_ID() 函数和 DB_NAME() 函数返回的元数据。

下表列出了对 public 角色可见的目录视图。

sys.partition_functions

sys.partition_schemes

sys.filegroups

sys.database_files

sys.partitions

sys.schemas

sys.sql_dependencies

sys.parameter_type_usages

sys.partition_range_values

sys.data_spaces

sys.destination_data_spaces

sys.allocation_units

sys.messages

sys.configurations

sys.type_assembly_usages

sys.column_type_usages

另请参阅

GRANT (Transact-SQL)
DENY (Transact-SQL)
REVOKE (Transact-SQL)
EXECUTE AS 子句 (Transact-SQL)
目录视图 (Transact-SQL)
兼容性视图 (Transact-SQL)