使用 AlloyDB 参数化安全视图管理应用数据安全

本文档介绍了如何在 AlloyDB for PostgreSQL 中使用参数化安全视图,以便您根据应用专用命名参数(例如应用用户凭据)限制数据访问。通过扩展 PostgreSQL 视图的功能,参数化安全视图可增强安全性和访问控制。这些视图还会自动对执行的任何查询强制执行一系列限制,从而降低从应用运行不可信查询的风险。

如需了解详情,请参阅参数化安全视图概览参数化安全视图教程

准备工作

本文档假定您已创建 AlloyDB 集群和实例。如需了解详情,请参阅创建数据库

您必须先执行以下操作,然后才能使用参数化安全视图:

  1. 申请对参数化安全视图的访问权限,并等待收到启用确认后再开始操作。

  2. 等待 AlloyDB 团队启用 parameterized_views.enabled 数据库标志,该标志会加载所需的扩展库。您必须先启用此数据库标志,然后才能开始。

    AlloyDB 团队启用 parameterized_views.enabled 数据库标志后,您的数据库会重启,以便这些更改生效。

  3. 使用 AlloyDB Studiopsql 在创建了参数化视图的任何数据库中创建 parameterized_views 扩展程序:

    -- Requires parameterized_views.enabled set to true
    CREATE EXTENSION parameterized_views;
    

    创建扩展程序时,系统还会创建一个名为 parameterized_views 的架构,以便 API 包含在该架构的命名空间中,并且 API 不会与现有 API 冲突。

创建带有参数的安全视图

如需创建带参数的安全视图,请按以下步骤操作:

  1. 运行 CREATE VIEW DDL 命令,如以下示例所示:

    CREATE VIEW secure_checked_items WITH (security_barrier) AS
    SELECT bag_id, timestamp, location
    FROM checked_items t
    WHERE customer_id = $@app_end_userid;
    

    在上面的示例中,参数化安全视图允许访问名为 /users/checked_items/ 的表中的三个列。该视图会将结果限制为 /users.id/checked_items.customer_id/ 与必需参数匹配的行。

    使用以下属性:

    • 使用 security_barrier 选项创建视图。
    • 如需限制应用用户,使其只能查看他们有权访问的行,请在 WHERE 子句中使用 $@PARAMETER_NAME 语法添加所需参数。一个常见的用例是使用 WHERE COLUMN = $@PARAMETER_NAME 检查列的值。
    • $@PARAMETER_NAME 表示命名的 View 参数。您在使用 execute_parameterized_query API 时提供其值。命名视图参数有以下要求:
      • 命名视图参数必须以字母 (a-z) 开头。
      • 您可以使用带重音符号的字母和非拉丁字母,也可以使用下划线 (_)。
      • 后续字符可以是字母、下划线或数字 (0-9)。
      • 命名视图参数不能包含 $
      • 命名视图参数区分大小写。例如,$@PARAMETER_NAME 的解读方式与 $@parameter_name 不同。
  2. 向允许查询该视图的任何数据库用户授予对该视图的 SELECT

  3. 向有权查询视图的任何数据库用户授予对包含视图中定义的表的架构的 USAGE 权限。

如需了解详情,请参阅使用参数化安全视图保护应用数据并控制对其的访问

为应用配置安全

如需使用参数化安全视图为应用配置安全性,请按以下步骤操作:

  1. 以管理员用户身份创建安全的参数化视图。此用户是 AlloyDB 数据库用户,负责为应用执行管理操作,包括数据库设置和安全管理。
  2. 创建一个新的数据库角色,用于对参数化安全视图执行查询。这是 AlloyDB 数据库角色,应用使用该角色连接和登录数据库,以及对参数化视图执行查询。

    1. 向安全视图授予新角色权限,这通常包括对视图的 SELECT 特权以及对架构的 USAGE
    2. 将此角色可以访问的对象限制为应用所需的一组最低公共函数和对象。避免向用户提供对非公开架构和表的访问权限。

    当您查询视图时,应用会提供所需视图参数的值,这些值与应用用户身份相关联。

    如需了解详情,请参阅创建数据库用户

查询参数化安全视图

如需查询参数化安全视图,请使用最适合您的用例的以下选项之一:

  • 基于 JSON:使用此 API 一次性运行查询并返回 JSON 行。
  • 基于光标:如果您有运行时间较长的查询或有大型查询,并且希望批量提取结果,请使用此 API。parameterized_views 扩展程序提供的 execute_parameterized_query 函数接受光标名称。
  • PREPARE EXECUTE 语句:适用于可使用不同的参数值多次执行的预编译语句。

如需查询参数化安全视图,您可以使用 parameterized_views 扩展程序提供的 execute_parameterized_query() 函数。

JSON API

此 API 存在限制,因为它会为给定查询声明一个游标。因此,查询必须与 PostgreSQL 光标兼容。例如,CURSOR API 不支持 DOSHOW 语句。

此 API 也不会按大小或返回的行数限制结果。

运行 execute_parameterized_query() 函数,其语法如下所示:

SELECT * FROM
parameterized_views.execute_parameterized_query(
    query => SQL_QUERY,
    param_names => ARRAY [PARAMETER_NAMES],
    param_values => ARRAY [PARAMETER_VALUES]
)

替换以下内容:

  • SQL_QUERY:一个 SQL 查询,其 FROM 子句引用一个或多个参数化安全视图。
  • PARAMETER_NAMES:要作为字符串传入的参数名称列表。
  • PARAMETER_VALUES:要传入的参数值列表。
    • 此列表的大小必须与 param_names 列表相同,其中值的顺序与名称的顺序一致。
    • 值的确切类型会根据查询和参数化视图定义推断出来。系统会根据需要尽可能对给定参数值执行类型转换。如果类型不匹配,系统会抛出错误。

该函数会返回一个 JSON 对象表。表中的每一行都等同于原始查询结果行的 ROW_TO_JSON() 值。

使用以下示例查询参数化安全视图:

SELECT * FROM
parameterized_views.execute_parameterized_query(
    query => 'SELECT * FROM secure_checked_items',
    param_names => ARRAY ['app_end_userid'],
    param_values => ARRAY ['40']
)

使用此 API 可通过结果大小(以千字节 [KB] 为单位)和行数来限制结果集的大小。您可以使用 parameterized_views.json_results_max_sizeparameterized_views.json_results_max_rows 配置这些限制。

CURSOR API

运行 execute_parameterized_query() 函数,该函数会创建并返回一个事务级范围的 CURSOR,您可以使用该 CURSOR 检索查询结果:

SELECT * FROM
parameterized_views.execute_parameterized_query(
    query => SQL_QUERY,
    cursor_name => CURSOR_NAME,
    param_names => ARRAY [PARAMETER_NAMES],
    param_values => ARRAY [PARAMETER_VALUES]
)

替换以下内容:

  • SQL_QUERY:一个 SQL 查询,其 FROM 子句引用一个或多个参数化安全视图。
  • CURSOR_NAME:要声明的光标的名称。
  • PARAMETER_NAMES:要作为字符串传入的参数名称列表。
  • PARAMETER_VALUES:要传入的参数值列表。此列表的大小必须与 param_names 列表相同,其中值的顺序与名称的顺序一致。值的确切类型会从查询和参数化视图定义中推断出来。系统会根据需要尽可能对给定参数值执行类型转换。如果类型不匹配,系统会抛出错误。

使用以下示例查询参数化安全视图:

  -- start a transaction as the that is the default lifetime of a CURSOR
  BEGIN;
  -- create a cursor called 'mycursor'
  SELECT * FROM parameterized_views.execute_parameterized_query(
   query => 'SELECT * FROM secure_checked_items',
   cursor_name => 'mycursor'
   param_names => ARRAY ['app_end_userid'],
   param_values => ARRAY ['40']
  );

  -- then, to actually fetch the results
  FETCH ALL FROM mycursor;
  -- end the transaction, which will clean up the cursor
  END;

返回的游标是 NO SCROLL 游标 WITHOUT HOLD。您无法使用游标以非顺序方式(例如向后)检索行。您无法在创建光标的事务之外使用该光标。

PREPARE 语句

使用 PREPARE .. AS RESTRICTED 命令创建引用参数化视图的预编译语句。这些预编译语句支持位置参数,并会在您执行它们时强制执行各种限制。如需了解详情,请参阅安全机制

此功能扩展了 PREPAREEXECUTE commands,以支持命名视图参数。使用预编译语句可避免每次执行语句时都进行解析、分析和重写的开销,这可以显著提升性能,尤其是对于频繁执行或复杂的查询。预编译语句是一种服务器端对象,可通过预编译和存储参数化 SQL 语句以供日后执行来优化性能。

此 API 存在限制,因为必须允许在 PREPARE 语句中使用该语句,这意味着仅支持 SELECTVALUES 语句。

此外,此 API 也不会按大小或返回的行数限制结果。

如需创建引用参数化视图的预编译语句,请运行 PREPARE .. AS RESTRICTED 命令:

PREPARE pquery (/POSITIONAL_PARAM_TYPES/)
        AS RESTRICTED query % a query that may refer to parameterized views
EXECUTE pquery (/POSITIONAL_PARAM_VALUES/)
      WITH VIEW PARAMETERS (VIEW_PARAM_NAME1 = VIEW_PARAM_VALUE1[, ...]);

替换以下内容:

  • POSITIONAL_PARAM_TYPES:在 RESTRICTED 查询中使用的一个或多个位置参数。
  • POSITIONAL_PARAM_VALUES:用于替换 PREPARE 语句中定义的定位参数的实际值。
  • VIEW_PARAM_NAMERESTRICTED 查询中引用的参数化视图预期的参数名称。
  • VIEW_PARAM_VALUE:传递给参数化视图的相应 viewParamName 参数的实际值。

如需在预编译语句中添加参数,您需要在 PREPARE 语句中提供数据类型列表。在准备好的语句中,您可以使用 $1$2 等按位置引用参数。

使用 EXECUTE .. WITH VIEW PARAMETERS 命令执行您之前使用 PREPARE .. AS RESTRICTED 命令创建的预先准备好的语句。如果创建该语句的 PREPARE 语句指定了位置参数,则您必须向 EXECUTE 语句传递一组兼容的参数。您必须在 WITH VIEW PARAMETERS 子句中传递参数化视图所需的任何命名视图参数。

使用以下示例查询参数化安全视图:

PREPARE pquery (timestamp) AS RESTRICTED SELECT * FROM secure_checked_items WHERE timestamp > $1;

EXECUTE pquery (current_date - 1) WITH VIEW PARAMETERS (app_end_userid = 40);
EXECUTE pquery (current_date - 30) WITH VIEW PARAMETERS (app_end_userid = 40);

对查询强制实施的限制

以下列出了对您使用查询参数化安全视图中所述选项运行的查询施加的一系列限制操作:

  • 禁止对任何 API(execute_parameterized_query 或使用 EXECUTE .. WITH VIEW PARAMETERS)进行任何递归调用,以便仅使用应用指定的值。此限制还可防止使用该查询规避给定一组参数值的安全封装容器。
  • 系统不允许启动新后台会话的某些扩展程序,包括 dblinkpg_cronpg_background 扩展程序。
  • 以下列出了允许使用的受限查询结构集:
    • 允许使用只读 SELECT 语句。
    • 允许使用只读 SHOW 语句、CALL 语句和 DO 语句。
    • 不允许使用 INSERTUPDATEDELETE 等 DML 语句。
    • 不允许使用 CREATE TABLEALTER TABLE 等 DDL 语句。
    • 不允许使用其他语句类型,例如 LOADSETCLUSTERLOCKCHECKPOINTEXPLAIN
  • 不允许使用 EXPLAIN 语句,以避免使用查询计划进行潜在的隐蔽通道攻击。如需了解详情,请参阅隐蔽通道

列出所有参数化视图

使用 parameterized_views 扩展程序,通过 all_parameterized_views 视图列出数据库中的所有参数化视图。此视图的输出与 pg_views 目录视图相同,但 all_parameterized_views 仅列出具有命名视图参数的视图。

如需列出参数化视图,请使用以下示例:

postgres=# select * from parameterized_views.all_parameterized_views ;
schemaname |      viewname      | viewowner |                       definition
-----------+--------------------+-----------+---------------------------------------------------------
public     | checked_items_view | postgres  |  SELECT checked_items.bag_id,                          +
           |                    |           |     checked_items."timestamp",                         +
           |                    |           |     checked_items.location                             +
           |                    |           |    FROM checked_items                                  +
           |                    |           |   WHERE (checked_items.customer_id = $@app_end_userid);

如需在 all_parameterized_views 中列出参数化视图,请确保参数化视图的定义中至少包含一个命名视图参数。

后续步骤