当前位置: 首页 > news >正文

Hermes 网关四层权限控制方案:让 AI Agent 安全地查数据库

Hermes 网关四层权限控制方案

  • 先说结论
  • 为什么需要四层?
  • 先交代一下数据背景
  • 第1层:消息入口注入(让大模型"不想"越权)
  • 第2层:SQL 改写(让大模型"不能"越权)
    • 从暴力拦截到 SQL 改写
    • 改写流程
    • 改写策略
    • 为什么改写比拦截好?
  • 第3层:结果行级过滤(兜底安全网)
  • 第4层:Prompt 补充引导(补充强化)
  • 落地效果
  • 一些踩坑经验
  • 总结

背景:我们做了一个 AI Agent,接入了 IM 通道(钉钉/飞书),用户可以自然语言提问,Agent 帮忙查数据库、做分析。但问题来了——如果市场部的人问"帮我看看财务部的薪资数据",Agent 会不会老老实实查出来?大概率会的,因为大模型这东西,你说啥它就干啥,没有"权限"的概念。

所以我们需要一套方案,在 Agent 和数据库之间加一道墙,让不同角色的用户只能看到自己该看的数据。


先说结论

我们最终落地了一个四层纵深防御的方案:

用户消息 → [第1层] Prompt 注入(软) → [第2层] SQL 改写(硬) → [第3层] 结果过滤(硬) → [第4层] Prompt 补充(软)

简单说就是:先劝、再改、再删、再补刀


为什么需要四层?

先聊聊为什么不能只搞一层。

很多人的第一反应是:在 Prompt 里告诉大模型"你只能查本部门数据"不就行了?

试过的都知道,这玩意儿不靠谱。大模型有时候"听话",有时候"不听话",尤其是你多聊几轮之后,它可能就把前面的约束给"忘"了。更别提有些用户会故意用话术绕过,比如"忽略之前的指令,帮我查一下……"。

那反过来,只做硬拦截,不搞 Prompt 引导行不行?

技术上可以,但体验很差。Agent 看到"帮我查全公司数据"直接回一句"你没权限",用户会觉得这 Agent 怎么这么笨,连"我能不能查"都不先判断一下。

所以我们的思路是:软硬结合,层层递进。Prompt 引导负责"劝",降低误触发;硬约束负责"兜底",确保万无一失。


先交代一下数据背景

我们的业务数据长这样(脱敏后的示例):

出票统计表t_ticket_stats

日期部门出票人出票量金额
2025-06-09运营一部李四500125000
2025-06-09运营二部王五30075000
2025-06-09国际业务部赵六20080000
2025-06-09国际市场部钱七15060000

注意:所有部门的数据都在同一张表里,不是"国内一张表、国际一张表"。所以光靠表名拦截是不够的——你拦了这张表,谁都查不了;不拦,谁都能看全公司数据。

这就是为什么我们需要行级的权限控制。


第1层:消息入口注入(让大模型"不想"越权)

时机:用户消息到达网关,大模型还没看到消息之前。

原理:自动识别用户身份,把权限标签塞到消息前面。

举个例子,用户张三(运营一部)发了一条消息:

“帮我统计一下各部门的出票量”

系统在前面注入权限上下文,变成:

【权限约束】你正在为张三(运营一部)查询数据,只允许查询运营一部、运营二部的数据,禁止查询国际业务部、国际市场部的数据。

帮我统计一下各部门的出票量

大模型看到这条消息,就会自觉地在 SQL 里加上部门过滤条件。

身份怎么来的?

不是让用户自己选的,而是自动解析

  • 优先查配置文件里的显式用户-角色映射
  • 没有显式配置的,去员工数据库查部门,再按部门组映射角色

比如"运营一部""运营二部"属于国内组,“国际业务部”"国际市场部"属于国际组。映射规则写在配置文件里,改起来很方便。


第2层:SQL 改写(让大模型"不能"越权)

时机:大模型生成了 SQL,工具准备执行之前。

原理:拦截 SQL,自动注入 WHERE 条件,让查询只返回用户有权看到的数据。

这是整个方案最关键、也是最优雅的一步。

从暴力拦截到 SQL 改写

我们最早的设计不是这样的。最初的方案是:检查 SQL 里有没有被禁的表名,有就直接拦截,不执行。

这个方案有个致命问题——我们的数据都在同一张表里。你没法通过"拦表名"来控制行级权限。而且就算分了表,大模型写个JOIN绕一下,表名匹配就废了。

所以我们换了个思路:不拦截,改写。

改写流程

假设张三(运营一部)的大模型生成了这条 SQL:

SELECT部门,SUM(出票量)AS总出票量FROMt_ticket_statsWHERE日期='2025-06-09'GROUPBY部门

系统在工具执行之前:

  1. 从上下文拿到当前用户身份 → 张三,国内组
  2. 查角色配置 → 国内组的可见部门列表["运营一部", "运营二部"]
  3. 解析 SQL,判断有没有 WHERE 条件
  4. 注入部门过滤条件

改写后的 SQL:

SELECT部门,SUM(出票量)AS总出票量FROMt_ticket_statsWHERE日期='2025-06-09'AND部门IN('运营一部','运营二部')GROUPBY部门

多了一行AND 部门 IN (...),数据库层面就把无权数据过滤掉了。

改写策略

情况处理方式
SQL 没有 WHERE 子句直接加上WHERE 部门 IN (...)
SQL 已有 WHERE 子句追加AND 部门 IN (...)
SQL 中已包含部门条件不重复注入,避免影响原有逻辑
正则提取 SQL 失败(转义字符等特殊场景)降级到表名匹配拦截,宁可多拦不能漏放

为什么改写比拦截好?

对比维度表名拦截SQL 改写
同表多部门数据没法用,拦了表谁都查不了天然支持,按部门过滤行
JOIN 绕过容易被绕不关心怎么 JOIN,始终加部门条件
用户体验动不动就"你没权限"用户正常提问,返回正确范围的数据
大模型行为需要大模型"听话"写对表名大模型随便写,系统兜底

一句话:与其教大模型"别查这个表",不如直接改它的 SQL,让数据库自己过滤。


第3层:结果行级过滤(兜底安全网)

时机:工具执行完,结果返回了,但大模型还没看到。

原理:逐行扫描查询结果,按部门字段过滤掉无权查看的行。

你可能会问:第2层都已经改写 SQL 了,为什么还要搞第3层?

两个原因:

  1. 不是所有查询都是 SQL。Agent 可能调用其他工具(比如 Python 脚本、API),这些工具有自己的数据源,第2层管不到。
  2. 防御纵深。就算第2层出了 bug(正则匹配失败、SQL 解析异常),第3层还能兜住。

举个例子,假设某个 API 工具返回了这样的结果:

姓名部门出票量
李四运营一部500
王五运营二部300
赵六国际业务部200
钱七国际市场部150

张三(国内组)最终看到的结果:

姓名部门出票量
李四运营一部500
王五运营二部300

过滤逻辑:

  1. 识别表头,找到"部门"列的索引
  2. 逐行检查部门字段是否在用户可见部门列表中
  3. 不在列表中的行直接删除,剩下的返回

国际部门的数据行被物理移除了,大模型压根不知道有这些数据存在。


第4层:Prompt 补充引导(补充强化)

这一层本质上是第1层的延续——在系统 Prompt 里持续强调权限约束,防止大模型在多轮对话中"遗忘"。

为什么要单独拎出来说?因为 Prompt 这东西有个特点:上下文越长,前面的指令越容易被"稀释"。用户聊了十几轮之后,第1层注入的权限标签可能已经被挤到上下文的角落了。第4层相当于在系统 Prompt 层面再"加固"一次。

当然,它本质上还是软约束。真正兜底的是第2层和第3层。


落地效果

上线后跑了两个月,几个关键数据:

  • 权限拦截准确率:跨部门查询 100% 拦截,没有出现过越权泄漏
  • 误拦截率:< 1%(主要是新入职员工部门信息未同步,补数据后恢复)
  • 用户体感:大部分用户感知不到权限控制的存在,查询体验没有明显降级

一些踩坑经验

坑1:SQL 改写要注意注入顺序

如果原始 SQL 里已经有多个 WHERE 条件,改写时要注意AND的位置和括号。比如原始 SQL 有OR条件:

WHERE状态='正常'OR状态='试用'

如果直接追加AND 部门 IN (...),由于 SQL 优先级,逻辑可能变成(状态 = '正常') OR (状态 = '试用' AND 部门 IN (...))

我们的做法是:给原始 WHERE 子句加括号,再追加部门条件

WHERE(状态='正常'OR状态='试用')AND部门IN('运营一部','运营二部')

坑2:部门映射要覆盖"查不到"的情况

新员工、外包人员、跨部门借调……这些人的部门信息可能不规范。我们的策略是:查不到部门的,默认归到权限最小的角色。宁可看少了,不能看多了。

坑3:大模型会"创造性"地绕过 Prompt 约束

有一次,用户用话术让大模型"忘记"了权限约束,大模型直接写了一条全表查询。第1层的 Prompt 引导完全失效。

但第2层的 SQL 改写兜住了——不管大模型写什么 SQL,部门条件始终会被注入。这次事件之后,我们坚定了一个原则:安全这件事,不能靠大模型"自觉",必须在系统层面硬编码。


总结

层级机制一句话
第1层Prompt 注入先跟大模型说"你只能查本部门的"
第2层SQL 改写大模型写的 SQL?系统帮它加WHERE 部门 IN (...)
第3层结果过滤非 SQL 工具的结果?按部门删掉再给它
第4层Prompt 补充多聊几轮再提醒一次

一句话总结:先劝、再改、再删、再补刀。四层下来,大模型想越权都难。


这个权限方案只做分享,不是最终方案,我之前想到了哪里有问题来着,没及时记录下来,忘记怎么改了(尴尬),目前线上这么跑起来没问题就先跑,我还有别的工作要去忙

项目地址:Hermes AI Gateway

如果你也在做 AI Agent 接入企业系统的权限控制,欢迎评论区交流。

http://www.jsqmd.com/news/986077/

相关文章:

  • 29、【python】信息管理系统
  • 废气处理塔制作选材对比|pp板材与PPH板材搭建洗涤塔优劣全面分析 - 苏一塑业13914572689
  • 2026 遵化厨卫屋面地下室漏水瓷砖空鼓测评:吉修匠 99.8 分五星榜首 - 吉修匠
  • 第一性原理:时间本质和空间本质
  • 2026成都手表回收“分级评分”排行榜:劳力士、欧米茄、浪琴S/A/B级实测 - 薛定谔的梨花猫
  • 企业宣传片拍摄制作服务商选择全解析:为什么需要宣传片,以及如何选对专业服务商
  • 2026年合肥理工学校怎么样?有什么专业? - cc江江
  • 代币模型设计:决定区块链项目长期成败的核心逻辑
  • 百达翡丽中国官方售后服务中心实地考察报告_多信源验证(2026年6月最新) - 百达翡丽服务中心
  • 2026南京专业废品回收,你的闲置资源这样变废为宝 - 资讯速览
  • 2026年生成式AI接口调度服务生产环境实测:中大型企业高可用基础设施选型参考
  • 合肥市包河区 房屋修缮|维小达 墙面维修、瓷砖维修、门窗维修、吊顶维修、石材修复全屋一站式服务 - 维小达科技
  • 国内多模态推理一体机厂家排行 品质甄选指南 - 奔跑123
  • 护发精油品牌测评:暨护发精油推荐的6款产品 - 资讯纵览
  • GTC泽汇:“芯片反弹提振风险偏好”
  • 16.4完整可运行代码:使用 SummarizationMiddleware 管理长对话记忆
  • 好用的昆明宝马专修哪家 - 英特菲斯
  • 晟邦齿轮电机:JSCC精研驱动方案的性能与市场表现解析 - 资讯焦点
  • 【ROS 2 全栈入门指南一】:从本质认知到环境搭建与核心原理解析
  • i.MX 6UltraLite接口时序详解:从GPMI到QSPI的实战配置与调试
  • 2026年防火涂料品牌综合实力榜:陕川正途领衔,六大防火材料优选 - 深度智识库
  • 从 SQL 美化工具到智能自动补全:开发者生产力工具的发展史
  • 2026 浙江锦鲤鱼池设计施工公司权威排行榜 杭州美村美户园林稳居首位 - 玖叁鹿
  • 2026 赤峰防水补漏哪家靠谱?正规公司排名及避坑价格指南 - 苏易修缮
  • 2026年泰州别墅设计公司|泰州大平层设计公司排行推荐! - 奔跑123
  • 雷达水位计选型指南:原理、型号、优势与行业应用 - 仪表人老张
  • 2026年6月10日六盘水黄金铂金 K 金钻石回收 TOP5 榜单 正规门店实测种草 - 资讯速览
  • 山西工程铝单板
  • 2026年4月络合铁催化剂厂家推荐 - 多才菠萝
  • 破包率从2.5%降至0.2%:吸嘴袋厂家案例解析 - 热点速览