使用安全视图

本主题介绍了将视图和物化视图定义为安全的概念和语法。

本主题内容:

安全视图概述

为什么要使用安全视图?

  • 对于非安全视图,内部优化可能会间接公开数据。

    视图的某些内部优化需要访问视图的基表中的基础数据。此访问权限可能允许通过用户代码(如用户定义的函数或其他编程方法)公开对视图用户隐藏的数据。安全视图不利用这些优化,从而确保用户无权访问基础数据。

  • 对于非安全视图,视图定义对其他用户可见。

    默认情况下,用于创建标准视图的查询表达式(也称为视图定义或文本)在各种命令和界面中对用户可见。有关详细信息,请参阅 与安全视图交互 (本主题内容)。

    出于安全或隐私原因,您可能不希望公开视图的基础表或内部结构详细信息。使用安全视图时,视图定义和详细信息仅对授权用户(即被授予拥有视图的角色的用户)可见。

何时应使用安全视图?

当视图专门指定用于数据隐私时,应将其定义为安全视图(即限制对不应向基础表的所有用户公开的敏感数据的访问权限)。

安全视图 应用于仅为方便查询而定义的视图,例如为简化用户无需了解基础数据表示形式的查询而创建的视图。安全视图的执行速度可能比非安全视图慢。

小技巧

在决定是否使用安全视图时,应考虑视图的用途,并考虑数据隐私/安全性与查询性能之间的权衡。

非安全视图如何公开数据?

使用以下小组件示例,假设用户只能访问红色小组件。假设用户想知道是否存在紫色小组件,并发出以下查询:

SELECT *
    FROM widgets_view
    WHERE 1/iff(color = 'Purple', 0, 1) = 1;
Copy

如果存在紫色小组件,则 IFF() 表达式返回 0。然后,除法操作由于除以零错误而失败,这允许用户推断至少存在一个紫色小组件。

创建安全视图

使用具有视图标准 DDL 的 SECURE 关键字定义安全视图:

与安全视图交互

查看安全视图的定义

安全视图的定义仅向授权用户(即已被授予拥有视图的角色的用户)公开。如果未经授权的用户使用以下命令或界面,则不会显示视图定义:

但是,对 SNOWFLAKE 数据库或其他共享数据库具有 IMPORTED PRIVILEGES 权限的用户可以通过 VIEWS Account Usage 视图访问安全视图定义。

具有 ACCOUNTADMIN 角色或 SNOWFLAKE.OBJECT_VIEWER 数据库角色的用户还可以通过此视图来查看安全视图定义。首选的最低权限访问方式是 SNOWFLAKE.OBJECT_VIEWER 数据库角色。

确定视图是否为安全视图

对于非物化视图,Information Schema 视图和 Account Usage 视图中的 IS_SECURE 列标识了视图是否为安全视图。例如,对于 mydb 数据库中名为 MYVIEW 的视图:

Information Schema:

select table_catalog, table_schema, table_name, is_secure
    from mydb.information_schema.views
    where table_name = 'MYVIEW';
Copy

Account Usage:

select table_catalog, table_schema, table_name, is_secure
    from snowflake.account_usage.views
    where table_name = 'MYVIEW';
Copy

(有关 INFORMATION_SCHEMA 视图和 ACCOUNT_USAGE 视图之间差异的一般信息,请参阅 Account Usage 与 Information Schema 之间的差异。)

您还可以使用 SHOW VIEWS 命令查看类似信息(请注意,视图名称不区分大小写):

SHOW VIEWS LIKE 'myview';
Copy

对于物化视图,请使用 SHOW MATERIALIZED VIEWS 命令确定视图是否为安全视图。例如:

SHOW MATERIALIZED VIEWS LIKE 'my_mv';
Copy

在查询配置文件中查看安全视图详细信息

安全视图的内部结构不会在 查询配置文件 (在 Web 界面中)中公开。即使对于安全视图的所有者也是如此,因为非所有者可能有权访问所有者的查询配置文件。

将安全视图与 Snowflake 访问控制搭配使用

可以使用 CURRENT_ROLECURRENT_USER 上下文函数将视图安全性与 Snowflake 用户和角色集成。下面的示例说明了如何使用角色来控制对表行的访问。除了包含数据 (widgets) 的表之外,该示例还使用访问表 (widget_access_rules) 来跟踪哪些角色有权访问数据表中的哪些行:

CREATE TABLE widgets (
    id NUMBER(38,0) DEFAULT widget_id_sequence.nextval, 
    name VARCHAR,
    color VARCHAR,
    price NUMBER(38,0),
    created_on TIMESTAMP_LTZ(9));
CREATE TABLE widget_access_rules (
    widget_id NUMBER(38,0),
    role_name VARCHAR);
CREATE OR REPLACE SECURE VIEW widgets_view AS
    SELECT w.*
        FROM widgets AS w
        WHERE w.id IN (SELECT widget_id
                           FROM widget_access_rules AS a
                           WHERE upper(role_name) = CURRENT_ROLE()
                      )
    ;
Copy

WHERE 子句限制了每个角色可以看到的小组件。

假设只能访问红色小组件的用户执行前面显示的查询:

SELECT *
    FROM widgets_view
    WHERE 1/iff(color = 'Purple', 0, 1) = 1;
Copy

安全视图的 WHERE 子句在用户查询中的任何 WHERE 子句之前执行。由于视图排除了紫色小组件,因此用户的查询永远不会生成除以零错误。

如果视图不安全,则 Snowflake 优化器可以对 WHERE 子句中的谓词重新排序。这可能允许用户查询中的谓词首先执行,这将允许发生除以零错误。

使用安全视图的最佳实践

安全视图可防止用户接触到由视图筛选的表行中的数据。但是,如果未仔细构造视图,数据所有者仍可能会无意中公开有关基础数据的信息。本节讨论一些需要避免的潜在陷阱。

为了说明这些陷阱,本节使用本主题前面示例中定义的示例 widgets 表和视图。

序列生成的列

生成代理项键的常见做法是使用序列或自动递增列。如果这些密钥向无权访问所有基础数据的用户公开,则用户可能能够猜测基础数据分布的详细信息。例如, widgets_view 公开 ID 列。如果 ID 是从序列生成的,则 widgets_view 的用户可以推断出在用户有权访问的两个小组件的创建时间戳之间创建的小组件总数。请考虑以下查询和结果:

select * from widgets_view order by created_on;

------+-----------------------+-------+-------+-------------------------------+
  ID  |         NAME          | COLOR | PRICE |          CREATED_ON           |
------+-----------------------+-------+-------+-------------------------------+
...
 315  | Small round widget    | Red   | 1     | 2017-01-07 15:22:14.810 -0700 |
 1455 | Small cylinder widget | Blue  | 2     | 2017-01-15 03:00:12.106 -0700 |
...
Copy

根据结果,用户可能会怀疑在 1 月 7 日至 1 月 15 日期间创建了 1139 个小组件(1455 - 315)。如果此信息过于敏感而无法向视图用户公开,则可以使用以下任一替代方法:

  • 不要将序列生成的列作为视图的一部分公开。

  • 使用随机标识符(例如由 UUID_STRING 生成)代替序列生成的值。

  • 以编程方式对标识符进行模糊处理。

扫描的数据大小

对于包含安全视图的查询,Snowflake 不会公开扫描的数据量(以字节或微分区为单位)或数据总量。这是为了保护信息免受仅有权访问数据子集的用户的影响。但是,用户可能仍能够根据查询的性能特征对基础数据的数量进行观察。例如,运行两倍时间的查询可能会处理两倍的数据。虽然任何此类观察充其量都是近似的,但在某些情况下,即使是这种级别的信息也可能不希望被公开。

在这种情况下,最好将每个用户/角色的数据具体化,而不是向用户公开基本数据的视图。对于 widgets 表,将为有权访问小组件的每个角色创建一个表,该表仅包含该角色可访问的小组件,并且将授予角色访问其表的权限。这比使用单个视图要麻烦得多,但对于安全性极高的情况,这可能是必要的。

安全视图和数据共享

将安全视图与 Secure Data Sharing 结合使用时,请使用 CURRENT_ACCOUNT 函数授权特定账户的用户访问基表中的行。

备注

CURRENT_ROLECURRENT_USER 函数与要共享给其他 Snowflake 账户的安全视图一起使用时,Snowflake 会返回这些函数的 NULL 值。原因是共享数据的所有者通常不控制共享视图的账户中的用户或角色。

语言: 中文