本文档介绍了 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) 结合使用。为确保用户只能通过视图查询数据,请执行以下操作:
- 启用 FGAC 并为应用创建数据库角色。
GRANT该视图的SELECT权限。- 确保未向
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;
创建参数化视图后,典型请求的过程如下:
- 应用在查询请求中设置安全上下文。上下文包含用于标识应用用户的信息,例如用户 ID 或角色。
- 应用对定义方权限视图执行查询。
- 该视图在
WHERE子句中使用SECURE_CONTEXT()函数,以根据安全上下文中提供的值过滤行。 - 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 中的参数化视图不包含安全屏障。虽然所有过滤条件都会在返回查询结果之前应用,但它们可能不会限制在内部查询处理期间访问哪些数据。