参数化视图概览

本文档介绍了 Spanner 中的参数化视图。参数化视图可让您根据查询传递的会话参数动态过滤数据,尤其适用于使用大语言模型 (LLM) 的智能体应用和系统。

参数化视图通过将上下文参数直接注入视图定义,扩展了数据库视图的功能。参数化视图可帮助您执行以下操作:

  • 将查询时上下文参数(例如用户或租户身份)传递到视图定义中。
  • 将查询结果限制为仅包含与所提供参数匹配的行。
  • 防止用户在生成的或临时 SQL 查询中绕过应用级数据过滤器。

如需了解详情,请参阅创建参数化视图。

参数化视图的工作原理

参数化视图使用参数将应用级上下文(例如用户 ID)安全地传递给数据库。当应用执行查询时,它会发送包含查询语句的上下文。Spanner 会在执行期间访问此上下文,但查询和应用用户都无法读取或修改它。

SECURE_CONTEXT() 函数提供 SQL 接口,用于在视图定义中访问这些安全参数。参数化视图需要定义方权限视图安全模型,其中视图使用 SECURE_CONTEXT() 访问值和过滤结果。

例如,如需根据发出查询的用户的 ID 过滤数据,您可以在视图的 WHERE 子句中添加以下内容:

CREATE VIEW MyUserData
SQL SECURITY DEFINER AS
(SELECT *
FROM AllUserData
WHERE UserID = CAST(SECURE_CONTEXT('user_id'), INT));

这样,应用就可以查看他们的数据,但无法查看其他人的数据。您还可以创建一个视图,让管理员可以查看任何用户的敏感度较低的数据:

CREATE VIEW SafeUserData
SQL SECURITY DEFINER AS
(SELECT UserID, AccountCreationTime, PublicProfileText
FROM AllUserData
WHERE SECURE_CONTEXT('role') = 'Moderator');

虽然您可以在视图查询定义中的任何位置使用 SECURE_CONTEXT(),但为了提高性能,最佳做法是在 WHERE 子句中使用它来过滤表或索引的前导键列。这可确保 Spanner 高效地将过滤逻辑推送到存储层。

默认情况下,直接在临时查询中查询 SECURE_CONTEXT() 函数会失败,除非数据库角色具有 spanner_secure_context_reader 角色。这样可以防止无特权的用户直接检查参数值。

建议的模式是将参数化视图与定义方权限视图和精细访问权限控制 (FGAC) 结合使用。为确保用户只能通过视图查询数据,请执行以下操作:

  1. 启用 FGAC 并为应用创建数据库角色。
  2. GRANT该视图的 SELECT 权限。
  3. 确保未向 public 系统角色授予对基表或视图的任何权限。

例如:

-- Create a role for the application user
CREATE ROLE pv_user;

-- Grant SELECT permission on the view to the role
GRANT SELECT ON VIEW MyUserData TO ROLE pv_user;

创建参数化视图后,典型请求的过程如下:

  1. 应用在查询请求中设置安全上下文。上下文包含用于标识应用用户的信息,例如用户 ID 或角色。
  2. 应用对定义方权限视图执行查询。
  3. 该视图在 WHERE 子句中使用 SECURE_CONTEXT() 函数,以根据安全上下文中提供的值过滤行。
  4. Spanner 仅返回与过滤条件匹配的行,从而有效地将查询结果过滤为与用户会话上下文关联的数据。

例如,应用可以使用其中一个 Spanner 客户端库在安全上下文中传递当前用户的 ID。以下示例使用 C++ 客户端库设置 user_id 安全参数:

(*request.mutable_secure_context())["user_id"] = "ca6095c4-1a68-44a8-9562-dd9e897326f0";

然后,应用会针对该视图执行标准 SQL 查询。该视图在其 WHERE 子句中使用此 user_id,以便仅返回属于该用户的记录:

--Query executed by the application
SELECT * FROM MyUserData;

参数化视图的优势

参数可帮助您实现以下目标:

  • 在多租户应用中隔离租户数据:使用参数可确保查询仅返回特定租户的数据。

  • 限制智能体 AI 查询:将自然语言查询限制为用户或租户的数据。

  • 使用临时凭据过滤数据:根据 Identity and Access Management (IAM) 中不存在的用户或租户 ID 限制数据访问。

  • 使用私密凭据进行过滤:使用查询所需的值过滤数据,这些值不应返回给最终用户。

安全风险缓释

当最终用户在数据库上运行不可信查询(例如自然语言查询)时,参数化视图有助于缓解安全风险。这些风险包括:

  • 恶意提示:用户可能会尝试操纵底层模型来访问所有应用数据。
  • 范围过宽泛的 SQL 查询:即使是出于善意的用户查询,大语言模型 (LLM) 也可能会生成泄露敏感数据的 SQL 查询。

通过使用参数化视图,您可以限制返回给特定应用用户的行范围,无论用户如何措辞。

最佳做法

请遵循以下做法,有效实现参数化视图。

  • 与定义方权限视图和 FGAC 结合使用:将参数用作综合安全模型的一部分,该模型包括定义方权限视图和精细访问权限控制角色。仅向该角色授予对视图的 SELECT 权限,并确保该角色和 public 系统角色对底层基表没有权限。

  • 对复杂上下文使用 JSON:如需传递结构化上下文(例如具有多个角色的用户),请将数据序列化为 JSON 字符串。将 JSON 字符串作为单个参数传递。使用 Spanner 的内置 JSON 或 JSONB 提取视图中的值。

  • 使用 SQL UDF 简化访问:如果您经常访问结构化 JSON 上下文中的字段,请创建用户定义的 SQL 函数 (UDF) 来封装提取逻辑。在视图中使用 UDF 可提高可读性和可维护性。

  • 使用 Model Armor 防范提示词注入:使用大语言模型根据不受信任的用户输入生成查询时,请使用 Model Armor 主动识别并阻止提示词注入和越狱尝试。

限制

参数化视图具有以下限制:

  • 实参类型:SECURE_CONTEXT() 函数需要一个字符串字面量实参。
  • 结果类型:SECURE_CONTEXT() 函数会返回一个字符串。
  • Spanner 功能交互:您不能在生成的列、默认列值表达式或用户定义的函数 (UDF) 中使用 SECURE_CONTEXT()。
  • 安全屏障:Spanner 中的参数化视图不包含安全屏障。虽然所有过滤条件都会在返回查询结果之前应用,但它们可能不会限制在内部查询处理期间访问哪些数据。

后续步骤