跳到主要内容

RAG 管道中的 PII 泄露:为什么你的聊天机器人知道它不该知道的事情

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的新内部聊天机器人刚刚告诉一名实习生整个工程部门的薪资范围。HR 总监没有配置错任何东西。没有人分享了不该分享的链接。系统只是... 检索到了它,因为实习生询问了“工程师的薪酬预期”。

这是大多数团队预料不到的 RAG 隐私失效模式。它不是传统意义上的漏洞 —— 而是检索工作方式与访问控制预期方式之间的根本不匹配。

核心问题:语义相似度不具备权限感知能力

在传统系统中,数据访问受显式规则制约。一个 SQL 查询包含 WHERE user_id = ?,并且只返回属于该用户的行。文件服务器在流式传输字节之前会检查权限。身份与数据之间的关系是结构性的 —— 它被植入到了查询本身之中。

RAG 管道的工作方式则不同。检索器接收查询,将其转换为嵌入(embedding),并查找具有高余弦相似度的分块(chunks)。它没有“这个分块属于 HR”或“该用户未获得薪酬数据授权”的概念。它只知道向量空间中的距离。

后果是严重的:用户询问一个关于工程角色的无辜问题,在语义上可能会落在受限的 HR 文档附近,从而导致该文档被拉入上下文窗口(context window)。随后 LLM 会热心地对其进行总结。没有任何环节触发警报。审计日志显示的是一次正常的检索。

这并非假设。关于 LLM 输出行为的研究显示,模型以大约 50% 的概率逐字复制检索到的文本。当检索到未经授权的内容时,有一半的时间它会近乎原封不动地出现在回复中。

为什么 SQL 风格的访问控制无法直接转化

大多数构建 RAG 系统的团队都拥有关系型数据库背景,这种思维模型被错误地迁移了过来。在 SQL 中,行级安全(row-level security)非常直接:为每一行标记所有者或组,在每个查询中添加谓词,大功告成。数据库引擎会自动执行它。

向量数据库在设计之初并没有考虑这种模型。几种结构性差异导致直接转化失效:

分块无法清晰地映射到行。 一个敏感文档会被拆分成几十个分块。这些分块可能跨越多个安全域 —— 例如一个邮件线程可能包含来自五个不同部门、具有五个不同访问级别的消息。当你按句子边界拆分它时,哪个 ACL(访问控制列表)适用于生成的分块?

相似度默认跨命名空间边界运行。 大多数向量存储将整个索引视为单个可搜索空间,除非你显式地对其进行分区。共享集合是阻力最小的路径,但它也是访问控制的单点故障。

缺乏约束支持。 大多数数据库中的向量数据类型不参与标准约束系统。你无法像对待关系表那样在模式(schema)级别强制执行访问控制。它必须在应用层实现,这意味着它可能会被遗忘、配置错误或被绕过。

没有自然的审计追踪。 SQL 查询会生成带有可检查谓词的结构化日志。向量相似度搜索不会告诉你为什么要返回某个特定的分块 —— 只会告诉你它足够接近。要重建用户通过检索接触到了哪些数据,需要大多数管道所缺乏的显式检测手段。

未经授权的检索是如何发生的

有几种不同的检索路径会暴露未经授权的内容,每种路径都需要不同的缓解措施。

语义重叠(Semantic overhang)。 用户的查询在语义上与受限文档相邻,即使该用户并无访问意图。“高级工程师的薪资范围是多少?”是招聘经理提出的一个完全合法的问题,但实习生提出的同样查询也会产生相同的嵌入。向量存储不知道提问者是谁。

共享索引中的跨角色污染。 当多个用户角色将文档摄取到同一个集合中,而没有进行针对分块的访问控制时,为其中一个角色进行的检索可能会引出本应给另一个角色的文档。语义空间将组织政策视为独立的内容折叠在了一起。

通过检索上下文进行的提示词注入(Prompt injection)。 嵌入在知识库中的恶意文档可能包含修改 LLM 行为的指令。如果该文档被检索到,它可能会影响后续的响应 —— 包括说服模型泄露其他检索到的内容。

嵌入反演(Embedding inversion)。 这是一个不太明显的威胁:向量嵌入本身也可能泄露信息。研究表明,通过代理模型,攻击者可以仅从嵌入中恢复原始文本的大部分内容。专有名词、技术术语和领域特定短语特别脆弱,因为它们占据了嵌入空间中独特且稀疏的区域。

构建行之有效的访问控制

唯一可靠的方法是分层防御——没有任何单一的控制措施是足够的,但多种控制措施结合起来会使未经授权的检索变得极其困难。

将分块 ACL 作为元数据

注入向量数据库的每个分块(chunk)都应携带一个访问控制列表(ACL)作为元数据。这至少包括源文档的分级、所属部门或团队,以及有权查看它的角色或用户 ID 列表。

在检索期间,在计算相似度得分之前(或之后,取决于具体数据库),对这些元数据进行过滤。大多数现代向量数据库都支持元数据过滤:Elasticsearch 的文档级安全性(Document Level Security)、Azure AI Search 的安全过滤器、Weaviate 的多租户(multi-tenancy)以及 Pinecone 的查询时过滤(filter-during-query)都实现了这种模式的变体。

前置过滤(在相似度搜索之前应用访问限制)效率更高,因为它减少了候选集。后置过滤(检索前 K 个结果然后丢弃未经授权的结果)实现起来更简单,但会浪费计算资源,并且当大部分前 K 个结果未经授权时,可能会产生极其稀疏的结果。

挑战在于,每个分块的 ACL 要求注入流水线能够理解文档权限——这意味着你的 RAG 系统需要与现有的身份和访问管理(IAM)系统集成。这并非一项小的工程投入,但它是确保在正确层级实施访问控制的唯一方法。

检索时的权限过滤

即使元数据中包含分块 ACL,你仍需在查询时通过将请求用户的身份注入到每次检索调用中来强制执行它们。这很容易出错:如果检索客户端是无状态的且不携带用户上下文,元数据过滤器就会被跳过。

一个可靠的模式是构建一个受访问控制的检索服务,介于 LLM 编排器和向量数据库之间。每个查询都会通过该服务,该服务负责:

  1. 从你的身份提供商中解析请求用户的角色
  2. 将这些角色转换为元数据过滤表达式
  3. 将过滤器附加到向量数据库查询中
  4. 仅返回通过过滤的分块

该服务是一个安全边界。它应该像安全边界一样接受测试——包括对抗性查询、权限提升尝试和跨租户隔离测试。

注入时的 PII 检测与脱敏

某些文档根本不应以原始形式注入。在进行分块和嵌入(embedding)之前,应对文档运行 PII(个人身份信息)检测。像 Microsoft Presidio 这样的库可以识别各种常见文档格式中的信用卡号、社会安全号码、姓名、地点、电话号码和其他实体类型。

在这个阶段的决策树是:

  • 完全舍弃文档:如果它是无法进行安全脱敏的原始数据导出。
  • 对特定实体进行脱敏:如果文档在去掉 PII 后仍有价值,则使用一致的占位符(例如 <PERSON_42>)替换它们。
  • 存储脱敏版本用于检索,同时将原始版本保留在独立的、非索引的系统中,以备合法需求之用。

使用基于 Transformer 的 NER(命名实体识别)进行上下文感知脱敏,比基于正则表达式的方法更准确,因为它可以处理歧义情况——在某种语境下 "Apple" 是公司名称,而在另一种语境下则是水果。脱敏在文档内部应保持一致,以便在替换后仍能保留实体关系。

注入流水线是 PII 控制中杠杆率最高的一环。一旦敏感数据被嵌入,你就是在从错误的一侧处理问题。

输出过滤作为最后一层防御

即使有了上游控制,输出过滤仍提供了最后一道防线。在 LLM 的响应到达用户之前,通过 NER 扫描器检测任何漏网的 PII。如果发现被标记的实体,则对其进行脱敏或拦截响应。

这不能替代上游控制——它无法阻止 LLM 在推理过程中包含未经授权的信息,只能防止其在输出中逐字显示这些信息。但它确实能捕捉到最明显的泄露,并在上游控制存在漏洞时提供有意义的信号。

向量嵌入的差分隐私:一个新兴选择

对于包含特别敏感数据的系统,越来越多的研究关注于向向量嵌入本身添加差分隐私(Differential Privacy)噪声。其直觉是,如果嵌入中注入了有界噪声,提取该向量的攻击者就无法高保真地恢复原始文本。

诸如覆盖度量分析高斯(CMAG)机制之类的技术可以添加经过校准的极小噪声,同时保留语义搜索的效用——研究实现方案在查询延迟开销可以忽略不计的情况下,仍能保持 99% 以上的召回准确率。权衡之处在于,极度相似的文档会变得略微难以区分,这可能会损害细粒度检索的精确度。

这种方法在向量嵌入本身就是一个威胁面时最为相关——例如,在向量存储跨越组织边界共享的联邦式或多租户部署中。对于大多数内部部署,分块 ACL 和注入时过滤在操作上更易于落地。

加固的 RAG 流水线是什么样的

将这些层组合在一起,一个隐私加固的 RAG 摄取流水线如下所示:

  • 文档通过一个与身份系统集成的摄取服务进入,以记录文档权限
  • 在分块前运行 PII 检测;敏感实体被遮掩或丢弃该文档
  • 创建分块时,将访问控制元数据与向量一并嵌入
  • 向量存储在查询时通过元数据过滤强制执行每个分块的 ACL
  • 检索服务强制注入用户身份,并在每次查询时按角色进行过滤
  • LLM 响应在交付前经过输出扫描器

这比大多数团队在第一阶段构建的基础设施要多。务实的顺序是:从摄取时的 PII 检测开始(杠杆率最高,能捕捉到最糟糕的情况),然后添加检索时的用户身份过滤,最后随着访问控制模型的成熟,添加每个分块的 ACL。

审计问题

一个被低估的问题:无论是为了事故响应还是合规性,你都需要能够回答“该用户上周二检索了哪些数据?”。

向量相似度搜索默认不会产生可查询的审计日志。你需要对检索服务进行监测,以记录:请求用户、查询嵌入(或原始查询)、检索到的分块 ID 以及这些分块所属的文档来源。这份日志是事故后调查得以进行的基础。

如果没有它,你将无法确定报告的数据泄露是否由你的 RAG 系统引起,也无法提供证据来证明它并非由此引起。

结语

RAG 流水线首先是检索器,其次才是语言模型。安全模型必须反映这一点。将 RAG 仅仅视为“带知识库的聊天机器人”,会导致访问控制在事后才被强行补上——通常是在发生事故之后。

构建这些系统的工程师了解 SQL、文件权限和 API 认证。RAG 访问控制的概念在本质上并没有什么不同。差距在于向量检索看起来简单得具有误导性——仅仅是相似度搜索,能有多难?——因此访问控制工作被降低了优先级,直到聊天机器人告诉了某人不该知道的事情。

References:Let's stay in touch and Follow me for more thoughts and updates