元数据可见性配置

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)

元数据的可见性仅限用户所拥有的安全对象,或已授予用户某些权限的安全对象。

例如,如果用户在表 SELECT 上授予权限(如 INSERTmyTable),则以下查询将返回一行。

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

但是,如果用户没有权限 myTable,查询将返回一个空的结果集。

元数据可见性配置的范围和影响

元数据可见性配置仅适用于以下安全对象:

  • 目录视图
  • 公开元数据的内置函数
  • 兼容性视图
  • 数据库引擎 sp_help 存储过程
  • 信息架构视图
  • 扩展属性

元数据可见性配置不适用于以下安全对象:

  • 日志传送系统表
  • 数据库维护计划系统表
  • 复制系统表
  • SQL Server 代理系统表
  • 备份系统表
  • 复制和 SQL Server 代理 sp_help 存储过程

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

  • 对系统视图的查询可能只返回行子集,有时返回空的结果集。
  • 元数据发出的内置函数(如 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 权限,或者在 SQL Server 2022 (16.x) 及更高版本中 VIEW SECURITY DEFINITION ,或 VIEW PERFORMANCE DEFINITION 位于适当的范围:对象级别、数据库级别或服务器级别。 因此,在前面的示例中,如果调用方具有 VIEW DEFINITION 权限 myTable,则存储过程将返回一行。 有关详细信息,请参阅 GRANTGRANT 数据库权限

也可以将存储过程修改为使用所有者凭据执行。 当过程所有者和表所有者相同时,便会应用所有权链,并且过程所有者的安全上下文便会启用对 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

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

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

从理论上讲,可以通过在查询中作谓词计算顺序来强制在错误消息中发出元数据。 此类 试验和错误攻击 的可能性并不特定于 SQL Server。 它由关系代数中允许的关联和通勤转换所暗示。 可以通过限制错误消息中返回的信息来降低此风险。 为了以此方式进一步限制元数据的可见性,可以使用跟踪标志 3625 启动服务器。 此跟踪标志限制错误消息中显示的信息量。 进一步有助于防止强制泄漏。 缺点是错误消息很简洁,可能难以用于调试目的。 有关详细信息,请参阅 数据库引擎服务启动选项跟踪标志

以下元数据不受强制披露的约束:

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

  • 用户定义的对象(如存储过程或触发器)的源定义。 仅当以下条件之一为 true 时,源代码才可见:

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

    • 用户在对象上未被拒绝VIEW DEFINITION权限,并且具有CONTROLALTERTAKE 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() 函数

  • 存储在 password_hashsys.sql_logins 列中的值。 没有CONTROL SERVER权限的用户,或者对于 SQL Server 2022(16.x)及更高版本,没有VIEW ANY CRYPTOGRAPHICALLY SECURED DEFINITION权限的用户,将在此列中看到一个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 the table itself
;

REVERT;
GO

DROP TABLE t1;
DROP USER testUser;

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

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

DB_ID()DB_NAME()函数返回的元数据对所有用户可见。

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

  • sys.allocation_units
  • sys.column_type_usages
  • sys.configurations
  • sys.data_spaces
  • sys.database_files
  • sys.destination_data_spaces
  • sys.filegroups
  • sys.messages
  • sys.parameter_type_usages
  • sys.partition_functions
  • sys.partition_range_values
  • sys.partition_schemes
  • sys.partitions
  • sys.schemas
  • sys.sql_dependencies
  • sys.type_assembly_usages