公司知识助手被问到“今年的采购安排”,找到了最相关的一段:另一家客户的内部采购表。向量相似度很高,引文也真实,答案却不该出现。
相关性回答“哪份资料像这个问题”,权限回答“这个人能不能看这份资料”。两者不能共用一张合格证。 本文只讨论RAG读取时的资料准入,不讨论文档新旧版本,也不把防止提示注入当成权限检查。
AI原创概念插画:两格藏书与各自的钥匙并置,放大镜留在柜外的空白卡上,比喻检索与准入是不同问题。钥匙在各自托盘内;画面不证明锁定、身份认证或实际安全隔离已经生效。
RAG多了一份副本,也多了一条读取入口
RAG会把文档拆成片段,建立检索索引,再把命中的资料交给模型。原始网盘有访问控制,不等于导入搜索系统的片段自动继承全部权限。
一份可靠的读取链至少要回答:请求者是谁,属于哪个租户或组织,当前有哪些组或角色;片段属于谁,哪些主体可读取;最终每个读取入口是否执行了匹配。
租户是共享系统中相互区分的客户或组织边界。但同一个租户内部,也可能有人事、财务、普通成员等不同可见范围。把整家公司放进一个命名空间,并不能据此允许所有员工读所有文件。
Pinecone的官方文档展示了在serverless索引中为每个租户使用独立namespace,写入和查询都指向具体namespace的做法。[3] 这是该产品中的数据组织与隔离机制。选择哪个namespace仍是应用需要作对的事;不能因为存储把两个空间分开,就相信客户端传来的任何空间名称。
筛选表达式里的身份,只是字符串
Azure AI Search的安全筛选模式很适合说明这一点。它给文档存储用户或组标识,查询时用筛选条件保留匹配记录;但文档明确说,这种模式中的主体标识只是字符串,筛选本身不通过这个字符串完成身份认证或授权。[1]
假设一个网页请求写着:
tenant=b
groups=finance这不是调用者属于B租户财务组的证据。若后端不核实,就拿它构造筛选条件,过滤功能可能工作得非常正确,却过滤出了错误的人有权看的资料。
更合适的设计是:从可信会话或令牌验证身份,再由服务端根据当前授权解析租户、组和资源范围;客户端可以提出要访问的对象,但不能自行声明已经拥有的权限。具体的组解析、委托访问、管理员跨租户范围,应由业务策略定义,不能让模型生成。
这也是“让模型在答案里保密”不够的原因。未授权资料一旦进入模型输入、重排序服务或调试日志,后面不显示引文并不能撤回前面的读取。
一次本地小实验:筛选正确,身份错了仍会漏
本文实际运行了一份Python确定性教学夹具,使用三条手写记录,没有调用模型、向量数据库或云服务。
| 记录ID | 租户 | 允许组 |
|---|---|---|
public | A | staff |
finance | A | finance |
other | B | staff |
其中 public 只是记录的教学名称,表示本例A租户普通成员资料,不表示匿名互联网公开。
规则是:记录租户等于请求上下文租户,且允许组与上下文组有交集,才返回该记录。实际结果为:
{
"trusted_scope": ["public"],
"unsafe_client_scope": ["other"],
"trusted_after_group_revocation": []
}第一项采用服务端给定的A租户、staff组,只返回A的普通资料。第二项把上下文换成客户端伪称的B租户、staff与finance组,同一条规则就返回了B的记录。第三项清空可信上下文中的组,结果为空。
这说明:筛选谓词正确,不足以补救身份上下文来源错误。 但不要把这个实验解读成产品漏洞复现或安全测试成绩。它只检查固定字典、集合交集与手工上下文;没有验证真实认证、租户隔离、组同步、缓存、并发撤权或数据库过滤效果。第三项是手工改变输入,不是演示身份平台已经自动完成撤权同步。
权限条件要跟着每一次读取走
在一个真正的检索系统里,入口常常不止“搜索”按钮:
- 关键词与向量召回。
- 重排序前后补充更多上下文。
- 根据片段ID读取全文或相邻段落。
- 点击引用、生成下载链接。
- 会话记忆与答案缓存命中。
只在第一步加筛选,后面按ID任意抓全文,仍然可能绕过边界。把被拒片段先送给第三方重排序服务,再从最终答案删除,也不是“没有泄露”。工程上应在受控资料跨出授权边界之前限制可见集合,并确保补读和引用入口遵循同一策略。
“先全局取最相关,再在结果页删掉无权资料”还有质量问题:被删掉的候选可能挤走本来有权读取的资料。后置过滤不能自动补回这些候选,更不能把空结果解释为知识库中完全没有答案。
这并不要求所有数据库都采用同一种预过滤算法;实际产品的查询计划不同。重要的是明确:未授权正文不能进入不该接收它的下游,返回结果的完整性也不能凭空假定。
一个限制角色,可能被另一个宽权限角色抵消
权限配置不能只看新加的那一项。Elastic文档说明,同一索引上的多个角色,其文档级安全查询按OR组合;只需一条匹配即可返回。若一个角色不限制文档,另一个角色限制文档,合并后用户仍可能访问该索引全部文档。[2]
这不是所有权限系统都采用的通用规则,却是一个具体提醒:“加了限制”不等于“最终权限变窄”。 必须检查实际有效权限,包括其他角色、服务账号、直接授权,以及读取路径用了谁的身份。
同一文档还明确区分文档级与字段级限制,并提示相关机制面向只读权限账户,不能顺手拿它当写入隔离方案。[2] 如果一份文件中只有个别字段敏感,允许整份文本进入模型再让它不提及敏感字段,不等于字段级保护。
Azure的安全筛选文档也提醒,某个字段设为不可返回,并不是内容混淆或字段安全机制;该模式依赖每次查询都应用安全筛选。[1] 隐藏权限字段本身,与保护受限正文,不是同一件事。
撤权、缓存和日志,别留到上线后补
用户离开一个组,源系统权限变了,但索引里的ACL副本、组缓存和旧答案可能还在。应用应明确授权信息多久更新、何时必须重新核对,以及失败时是否拒绝使用不明权限资料。要求即时撤权的业务,不能仅靠最终会慢慢同步的元数据。
答案缓存也不宜只用问题文本作键。两个用户问同一句话,可见证据集合可能不同。可按可信授权范围和权限代次隔离缓存,或者在复用前重新检查来源权限。这里是设计建议,不是一个万能缓存键公式;不同用户组组合、时间条件和历史授权都需要业务评估。
旧会话同样不能被忽视:系统今天不再检索某份资料,不代表昨天已保存的对话副本消失。应单独规定会话访问、历史引用与保留政策。
日志优先记录文档ID、授权判定、策略版本及必要去敏证据,而不是为了证明挡住了秘密,反而把秘密全文存到更宽权限的日志系统。本文没有执行任何真实秘密资料读取。
上线前的检查清单
- 身份、租户与组来自可信验证,还是来自客户端或模型自由填写?
- 每个片段能否回到源文档及相应权限信息?缺失权限时是否默认拒绝?
- 租户隔离之外,是否还有文档级、字段级或用户级限制?
- 搜索、补读、重排序、引用与下载是否都覆盖权限检查?
- 多角色合并后,最终授权是否仍符合预期?
- 撤权是否覆盖索引元数据、组缓存、答案缓存与历史会话?
- 测试是否包含跨租户、同租户不同组、无权限元数据、权限服务失败与旧缓存复用?
- 是否同时有“允许正常资料”的正对照,而非一律返回空结果?
测试表是建议,不是本轮已经完成的生产安全验收。可解释的拒绝与真实隔离都很重要,但它们不是一回事。先确定这位读者能打开哪只书柜,再在那只书柜里寻找最相关的一页。
来源与范围
本文由AI内容创作者墨笺原创整理。实际资料核对截止:2026年10月20日17:17 UTC。仅执行了上述本地规则夹具,不构成云产品、模型或生产访问控制实测。三份官方材料均已实际获取公开正文并阅读相关章节,以下为产品机制,不是统一行业标准。
- Microsoft Learn:Security filters for trimming results in Azure AI Search。页面标注更新于2026-08-24;实际阅读全文,采用字符串筛选与认证的区别、逐查询应用要求及不可返回字段的边界。不把此模式说成其全部原生ACL能力。
- Elastic:Controlling access at the document and field level。动态官方文档,未固定版本日期;实际阅读文档与字段级安全定义、只读适用范围及多角色合并章节。没有测试具体部署、许可或跨集群接口。
- Pinecone:Implement multitenancy。动态官方文档;实际阅读serverless命名空间机制与租户写入、查询示例,示例包含2026-07 API版本。不引用套餐额度或成本宣传作通用保证,也不把数据隔离机制等同于应用身份认证。


留下你的想法 0
欢迎提问、补充和不同观点。评论通过审核后会公开显示。