大多数AI助手的演示,都是把模型架在数据库上面。给智能体配一个“查询”工具,用户提问,模型写查询语句。演示时效果很好。到了生产环境,这意味着用户的判断和别人的数据之间,只隔着模型这一道关。
我正在把AI智能体做进The Arsenal,一个面向寿险代理人的平台。第一版故意做得很“无聊”:只读性能数据、回答问题,什么都不写。但即便是只读智能体,也坐在客户记录之上,所以在智能体成型之前,我按OWASP的LLM应用十大风险清单逐条过。这篇讲第二条——敏感信息泄露,以及由此得出的设计决策。
数据访问层是唯一的门
模型从不接触数据库。它只调用一小批窄接口,比如“取我本周的管道统计”。没有通用查询工具,没有裸SQL,没有例外。如果某个问题没有对应的函数,智能体就答不了——这正是设计意图。
所有安全问题都收敛到一个地方:数据访问层放行了什么。
身份来自会话,绝不来自模型
模型会索要线索ID、客户ID这类东西。那些是参数。真正承担安全职责的字段是“谁在问”,而模型从不提供它,由已认证的会话提供。数据访问层把调用者身份盖在每条查询上,并按该身份允许的范围过滤行。
如果模型能传“用户等于Alex”,它就能传任何人。所以它压根不该传用户。
字段只打一次标签,且默认关闭
一个KPI问题永远不需要客户的电话号码或出生日期。所以模型根本不该收到它们。它没见过的东西,泄不出去。
与其给每个函数手写白名单,不如让模式里的每一列都带一个标签:公开、生产、客户PII。每个函数声明自己的层级,数据层拒绝返回高于该层级的任何内容。真正要紧的规则是:有人新增一列却忘了打标签时怎么办——它会被当作PII,永不返回。忘打标签的结果是一个缺失的数字,而不是一次泄露。
模型说“不”不算控制
智能体会礼貌地告诉用户,电话号码不在范围内。那是用户体验,不是安全。模型拒绝是我要求的行为;数据层永不返回该字段才是保证。就算提示注入说服模型放弃拒绝,它依然什么都拿不到。
那些会泄露的小地方
- 错误信息:用户看到通用提示,真实错误带着请求ID进服务器日志。
- 存在性泄露:“我不能给你看Maria Lopez的记录”等于确认她是客户。越界查询返回的错误,和打错字时一模一样。
- 对话记录与日志:两者都含客户数据,因此套用同样的访问控制,对话记录另加三十天清除。
这套设计没解决什么
它假设数据访问层本身是对的。在测试之前,这只是假设,所以审计阶段包括:以某个下级用户的身份登录,试着通过模型拉取另一个代理人的数据行。它也不覆盖第二版给智能体写入能力之后的情况——那会把上面每个问题重新打开。至于模型提供商自己的留存与训练条款,那是合同审查的事,不是改代码能解决的。
这是一个寿险平台里一个智能体的第一版。我正按同样的方式过完OWASP清单剩下的条目,边做边写。目标是恰好从保险起步的智能体安全,而不是保险安全。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.