状态:✅ 已完成 前置阅读:01~11 全部(尤其 03 架构分析),以及 maas-safe-doc 仓库的三篇网关侧笔记:
../../maas-safe-doc/安全护栏/poc/网关安全插件-1-基础功能验证.md、网关安全插件-2-高级能力验证以及存在的问题分析.md、网关脱敏插件实现原理分析-ai-data-masking-脱敏与还原.md日期:2026-09-14 素材来源:JoySafety 源码核实(路径均逐一 Read/Grep 验证)+ Higress 插件侧引用自上述脱敏原理笔记 读者定位:要把"网关插件 / 脱敏插件 / JoySafety"三条线组装成一套生产方案的读者。本篇以架构图和决策表为主,源码坐标用于支撑每个机制结论
〇、一句话总览
网关插件管"流量",脱敏插件管"数据",JoySafety 管"内容"。
| |
类比:机场安检——网关是入口闸机(验票、限流、黑名单),脱敏是行李打包(贵重物品封存、凭条可取回),JoySafety 是安检仪+人工复检(X 光粗筛、开包精检、专家会诊)。
一、三层各自的定位
1.1 定位对照表
| 维度 | 网关安全插件(Higress) | 脱敏插件(ai-data-masking) | JoySafety |
|---|---|---|---|
| 防护对象 | 流量入口 | 敏感数据(PII/密钥) | 内容语义风险 |
| 核心问题 | 谁来访问、来多少、是不是 Web 攻击 | 数据出不出域、能不能还原 | 文本合不合规、有没有注入 |
| 技术形态 | Envoy/Higress 插件(WAF=ModSecurity+CRS) | Rust 编译 WASM,网关内嵌运行 | 独立部署的 Java/Python 微服务集群 |
| 检测手段 | 规则匹配(CRS 规则集、IP 名单、计数器) | 结巴分词+HashSet、Grok/正则、HMAC-SHA256 | AC 自动机、BERT 分类、向量检索、LLM 多轮 |
| 单次开销 | 微秒~毫秒 | 毫秒(本地 WASM,无网络调用) | 词库 ~40ms,BERT 生产 ~200ms(见 02 篇实测) |
| 策略载体 | 网关控制台 YAML | 同左(replace_roles/system_deny) | MySQL 版本化配置 + DAG YAML |
| 拦截粒度 | 请求级(403/429) | 词级(替换)或请求级(deny) | 词/句/会话级,riskCode 细分 14+ 类 |
| 失败倾向 | 拒绝服务(fail-close 基因) | 可配(deny/replace 两档) | ignoreError 可配,默认容错(fail-open 基因) |
1.2 为什么需要三层而不是一层
三道防线对应三种成本—能力曲线,缺一不可:
- 网关层最便宜也最快,但只能做模式匹配。SQL 注入、XSS、IP 封禁、QPS/TPM 限流在这里拦,一次拦截成本几乎为零——POC 验证 6 项 WAF 用例全部 403 拦截(网关安全插件-1,TC01~TC04)。
- 脱敏层解决的是"内容合规管不了"的问题。JoySafety 没有脱敏替换能力(网关安全插件-2 第 4.2 节实测确认:“缺少 Higress 脱敏插件的脱敏替换功能”),身份证/手机号/API Key 必须在出域前由脱敏插件替换或哈希。脱敏插件源码证实其三档机制:
DenyWord(结巴分词+HashSet 拦截,deny_word.rs:63-70)、replace(正则替换为固定值)、hash(HMAC-SHA256 可逆脱敏,ai_data_masking.rs:431-486)。 - JoySafety 解决的是"规则看不懂"的问题。变体辱骂、暗示性暴恐、祖母漏洞式提示词注入,规则引擎无解,必须上模型和知识库。02 篇实测:BERT 对"哪里有卖枪支的"判 riskCode=1002(置信度 0.9989),对祖母漏洞判 riskCode=201(置信度 0.994)——这两类网关层完全拦不住。
1.3 各层在本系列/姊妹篇中的出处
| 层 | 深入笔记 |
|---|---|
| 网关插件 | 网关安全插件-1(基础功能 POC)、-2(高级能力与问题分析) |
| 脱敏插件 | 网关脱敏插件实现原理分析(Rust/WASM 源码级) |
| JoySafety | 本系列 03(架构)、04(DAG)、05(free_taxi)、06(敏感词)、07(知识库)、08(注入攻防) |
二、完整请求链路设计
2.1 全链路时序图
一条 LLM 对话请求穿过三层防线的完整旅程(入向审核采用 JoySafety sync 模式,在调用模型之前拦;出向采用 free_taxi 模式,不阻塞流式输出):
| |
设计说明(与提纲出入处):提纲原文把"JoySafety 输入审核"放在 LLM 之后。实际方案将其放在 LLM 之前——输入审核的意义就是在token消耗发生前拦截(命中即不再调模型,省钱省延迟),这与 JoySafety
sync模式的定位一致:“同步跑完整 DAG 返回结果,适用输入审核(发出去之前拦)"(03 篇 3.5 节)。提纲中的顺序在"先过模型再回头审输入"的反模式里没有意义,本篇以实际代码语义为准做了修正。
2.2 JoySafety 侧的两个视角回顾(详见 03 篇)
配置流转(配置期):
| |
请求流转(执行期),入口 DefenseApiV2Controller(safety/safety-api/src/main/java/com/jd/security/llmsec/contoller/DefenseApiV2Controller.java:31-33):
| |
随后进入 DAG 主循环 FunctionExecutorImpl.doExecute()(FunctionExecutorImpl.java:289)——while (curNode != null) 逐跳执行,每轮先查整体超时(:297-299),节点异常按 ignoreError 决定抛出还是跳过(:312-323),router 返回 null 即终结。
2.3 出向为什么必须是 free_taxi
流式输出场景,同步检测意味着"攒完整段再返回”,首 token 延迟直接报废。JoySafety 的解法是 free_taxi(03 篇 3.5 节、TaskExecutorImpl.java:78):
- 请求侧只做
submit(Redis lpush 投递)立即返回,检测从同步路径上摘掉; - 200 线程池消费(
TaskExecutorImpl.java:56-63),按 sessionId 抢 Redis 分布式锁(storageService.lock,:88,锁 10 秒,:75)实现多实例互斥; - 检测结果 lpush 进会话结果队列,下一次请求搭便车带回(
DefenseApiV2Controller.java:108); - 会话结束发
sync请求(content='$')收尾取全量。
代价是结果滞后一条消息,且跨 chunk 的 unsafe 内容识别能力有限(网关安全插件-2 第 4.1 节明确指出该短板,并建议与脱敏插件的滑动窗口机制结合)——这正是三层互补的典型场景:出向的实时底线由脱敏插件的流式敏感词检测(MsgWindow 累积缓冲区检测)兜住,深度语义检测由 free_taxi 异步补齐。
三、职责边界与不重复建设
3.1 放哪层的决策表
| 检测项 | 放哪层 | 理由(成本/准确率/延迟权衡) |
|---|---|---|
| SQL 注入/XSS/路径穿越/命令注入 | 网关 WAF | CRS 规则成熟、微秒级、与 LLM 语义无关。POC 实测 5 类攻击全部 403 |
| Content-Type 校验、空 UA | 网关/前置 Nginx | 纯协议层检查,不重复建设(POC 明确"不在 WAF 层重复配置") |
| IP 黑白名单 | 网关 | 连接级信息,越靠前越省资源。注意 POC 发现黑白名单互斥、白名单≠跳过审核 |
| 租户 QPS/TPM 限流 | 网关 | 需要全局计数(Redis 集群级限流插件),JoySafety 的 RateLimiter 是单实例内存级(03 篇 3.1),只作兜底 |
| PII(身份证/手机/邮箱/IP)脱敏 | 脱敏插件 | JoySafety 无替换能力;正则微秒级,放模型层是纯浪费 |
| API Key/密钥出域 | 脱敏插件(hash+restore) | 可逆需求只有 mask_map 机制能满足 |
| 粗粒度敏感词(涉政/赌博黑词) | 两层都放(见 3.2) | 网关侧拦截成本≈0 先挡一波;JoySafety 词库做黑白灰精细化管理 |
| 变体辱骂/暗示性违规 | JoySafety BERT | 语义问题,规则无解 |
| 提示词注入(祖母漏洞等) | JoySafety 注入模型 | 需要红蓝军对抗训练的专门模型(08 篇) |
| 红线问题代答 | JoySafety RAG | 需要知识库+一致性校验双保险(07 篇) |
| 多轮上下文风险 | JoySafety multi_turn_detect | 需要会话历史(Redis),网关无状态做不了 |
| 业务级 HMAC 鉴权 | JoySafety(审核接口) | 网关管租户身份,JoySafety 管业务 accessKey/secretKey,各管一段 |
3.2 重叠能力的分工:敏感词两层都放,但不重复
三层在"敏感词"上有能力重叠(网关安全插件-2 第五章有完整对比表),分工原则是网关挡子弹、JoySafety 做手术:
| 维度 | 脱敏插件内置词库 | JoySafety 敏感词服务 |
|---|---|---|
| 匹配方式 | 结巴分词+HashSet,contains | AC 自动机(SensitiveWordDetector.java:14-15,ahocorasick Trie),支持 contain/equal/regex/compound 四种(safety-admin/docs/tables.sql:9) |
| 处置策略 | 拦截(deny)或替换(replace/hash) | 黑白灰名单+exclude(tables.sql:10),白名单命中直接放行短路 |
| 词库运营 | 静态内置+配置自定义 | MySQL 持久化,admin 动态增删,keywords 服务定时轮询重建(SensitiveWordsManageServiceImpl.java:194 @Scheduled) |
| 定位 | 出域底线(数据不走) | 内容风控(语义判定) |
实操建议:网关侧只放零容忍、无歧义的短词黑名单(错了代价高的放这里,fail-close);JoySafety 侧放全量词库+黑白灰策略,承接需要场景过滤、优先级排序的精细判定(06 篇)。
3.3 脱敏与内容审核的数据流衔接
关键决策:先脱敏还是先审核? 推荐顺序"脱敏请求侧 → JoySafety 输入审核"(即 2.1 图的顺序),理由与代价:
- ✅ PII 不进 JoySafety 的日志/会话历史/结果缓存——JoySafety 会把会话历史写 Redis、按内容 MD5 缓存结果 15 分钟(03 篇 3.6),明文手机号进去就是二次泄露面;
- ⚠️ 代价:审核看到的是脱敏后文本(手机号→
*****),对"报出自己手机号求回拨"这类语义判定有轻微影响。可接受——PII 本身不是内容风险,语义审核本来就不需要知道号码是多少; - ❌ 反序(先审后脱敏)的问题:审核链路成为明文 PII 的新出口,且脱敏替换可能把黑词切成两段逃逸审核(如正则替换恰好切分敏感词),必须在审核之前完成文本改写。
出向衔接:JoySafety free_taxi 检测的是脱敏态的输出流(hash 串不影响语义判定),脱敏插件在最后一个环节做 mask_map 还原——还原发生在审核之后,审核结果不受还原影响。
四、每层故障的兜底策略
4.1 fail-open vs fail-close 决策表
| 故障场景 | 默认行为 | 建议取向 | 理由 |
|---|---|---|---|
| 网关 WAF/限流插件异常 | 网关层故障通常表现为整个入口不可用 | fail-close | 入口挂了等于服务下线,不存在"放过去"选项;重点是多副本+健康检查 |
| 脱敏插件异常(WASM panic/配置错误) | 请求中断 | fail-close | 它的职责是"数据不出域",放行=明文 PII 直送外部 LLM,宁可误伤不可泄露 |
| JoySafety 单 skill 挂(bert/keywords/knowledge) | fail-open:DAG 节点 ignoreError: true 时异常被吞掉继续走(FunctionExecutorImpl.java:319-323),演示策略全部节点都是 ignoreError: true(docs/strategy_example.yml:23,65,107,114) | 看节点角色 | 词库节点挂了fail-open可接受(后面还有模型);最后一道模型节点挂了必须告警,否则等于裸奔 |
| JoySafety 单 skill 慢(超时) | fail-open:parallel 内 Future.get(curTimeout) 超时丢弃该子项结果(ParallelFunction.java:130-136) | fail-open + 阈值监控 | 02 篇坑 4 的教训:超时丢弃是静默的,必须靠耗时分布监控发现(该拦没拦且耗时诡异停在 2s 就是信号) |
| JoySafety 整体挂(api 不可达) | 业务方调审核接口失败 | 建议 fail-close,配额降级 | 输入审核 fail-close 拦不了就拒答;出向 free_taxi 本来就是异步,api 挂了影响的是检测结果回流,可短窗 fail-open |
| admin 挂了 | 天然 fail-open:admin 不在请求链路上,api 靠内存缓存继续跑(03 篇认知 1) | fail-open(架构自带) | 只是不能再改配置;且 shouldUpdate 有保底:拉取失败/配置为空时保留旧配置不丢(DynamicConfigService.java:116-119 注释"防止出现异常时丢失配置") |
| MySQL/Redis/Vearch 挂 | api 不直连 MySQL 无影响;Redis 挂=free_taxi/会话历史/结果缓存全瘫;Vearch 挂=知识库能力瘫 | Redis 必须高可用 | 开源版全部没挂数据卷(03 篇 7.2 坑 3),docker compose down 即丢全部配置——生产化第一项改造(11 篇) |
4.2 兜底策略的三条元规则
- 数据类故障(脱敏、密钥)一律 fail-close,内容类故障可按业务容忍度选 fail-open——泄露不可逆,误拦可申诉。
- fail-open 必须配监控,否则就是"静默裸奔"。JoySafety 的失败全部是静默的:超时丢结果(
ParallelFunction.java:132-135只打 error 日志+计数)、异常忽略(FunctionExecutorImpl.java:320同样只打日志)。好在框架内置了MonitorAlarmService计数(如parallelIncr、functionIncr、apiPlanIncr),把这些计数接入告警是生产化的必修课。 - 降级不等于关闭:JoySafety 挂了可以临时降级为"只过网关词库"(网关侧词表保持一份最小黑名单的意义就在这里);脱敏挂了没有降级方案,只能拒答——所以脱敏插件的规则集要刻意保持小而稳。
五、统一审计与运营
5.1 三层日志汇集
三层各有一套"拦截证据",格式完全不同,统一审计的第一步是用 requestId 贯穿:
| 层 | 拦截证据 | 关键字段 |
|---|---|---|
| 网关 | WAF 审计日志、限流 429 日志 | 命中规则 id(如 CRS 942/930)、租户、IP |
| 脱敏 | 网关日志中的 deny_message 返回、替换计数 | 命中词/规则、是否 restore |
| JoySafety | 审核响应 + MonitorAlarmService 计数 | riskCode(1002 暴恐/1006 辱骂/201 注入…)、riskCheckType(keyword/single_label_pred/rag_answer)、hitWord、置信度(02 篇实测响应样例) |
落地方案:网关和脱敏在入口生成/透传 X-Request-Id,JoySafety 请求体自带 requestId 且参与 HMAC 签名(SignUtil.java:45),三层日志按 requestId join 进同一个 OLAP/ES 索引。
5.2 拦截事件归因
收到一条拦截告警后的归因决策树:
| |
5.3 策略分层维护节奏
| 层 | 策略载体 | 变更方式 | 建议节奏 | 生效延迟 |
|---|---|---|---|---|
| 网关 WAF | 控制台 YAML | 先 DetectionOnly 观察 1-3 天再切 On(POC 建议) | 月级/随 CRS 升级 | 秒级 |
| 网关限流 | 控制台 YAML | 直接改 | 随业务活动(大促前压测调整) | 秒级 |
| 脱敏规则 | 控制台 YAML | 新增规则先小流量灰度;规则集刻意保持小(4.2 条 3) | 季度级,谨慎 | 秒级 |
| JoySafety 词库 | MySQL(admin API) | upsert→online,走黑白灰策略 | 周级/舆情驱动 | ~60s(keywords 轮询,SensitiveWordsManageServiceImpl.java:194) |
| JoySafety DAG/能力 | MySQL 版本化状态机 | active→newVersion→update→upgrade(03 篇 4.2,online 禁原地改) | 按需,灰度可用 AB 按 dagVersion 指定版本 | 最长 ~60s(api 轮询,DynamicConfigService.java:65;原子能力类变更实践上需重启 api,02 篇坑 5) |
| JoySafety 模型 | HuggingFace 模型目录 | 换模型目录+重建容器 | 跟随官方模型迭代(如注入模型二分类→三分类) | 重启级 |
六、系列总结与展望
6.1 12 篇知识地图回顾
| |
一句话收束整个系列:JoySafety 的内核是"配置版本化 + DAG 编排 + 无状态 skill"三板斧,把它放进三层防护体系里,它负责的是最需要智能、也最贵的那一段。
6.2 官方 roadmap 展望(README.md:346-353 “📅计划” 一节,原文摘录转述)
| 方向 | 官方表述要点 | 对三层体系的意义 |
|---|---|---|
| 安全审核大模型 | HuggingFace 已开源部分模型 JSL-joysafety-v1(README.md:349),后续 JoySafety 集成该系列实现大模型风险合规审计 | 内容层从"BERT 小模型分类"升级到"审核专用大模型",语义判定能力质变;对网关/脱敏层无影响,接口层不变 |
| 大模型安全评测 | 覆盖《生成式人工智能服务安全基本要求》5 大类 31 小类风险类型(README.md:351) | 给三层体系提供量化验收标准——每层拦哪几小类、漏哪几小类,可以按国标口径出报告(本系列 15 篇红队评测的对接点) |
| Agent 安全防护 | 身份与权限管理、数据与记忆防护、工具与执行安全、MCP 代码安全检测、供应链与协议安全(README.md:353) | 三层体系的前瞻缺口:Agent 场景下"工具调用参数"和"MCP 协议"既不是纯流量也不是纯文本内容,现有三层都罩不全,是下一个架构演进点 |
6.3 留给实践的开放问题
- free_taxi 的跨 chunk 漏检与脱敏插件滑动窗口如何组合(网关安全插件-2 第 4.1 节的方向),需要一次联合实验;
- 脱敏插件流式响应"拦截后 finish 时吐出剩余内容"的疑似 Bug(网关安全插件-2 第 3.1 节)需要上游修复或规避,出向兜底策略据此调整;
- Agent 安全防护落地时,三层模型的"流量/数据/内容"划分需要扩展第四层"行为/工具"——这是官方 roadmap 给出明确信号、但开源代码尚未覆盖的领域。
附:本篇引用的源码坐标汇总
| 机制 | 位置 |
|---|---|
| 审核入口/限流/验签/模式分派 | safety/safety-api/src/main/java/com/jd/security/llmsec/contoller/DefenseApiV2Controller.java:31-120 |
| HMAC-SHA1 签名 | safety/safety-basic/src/main/java/com/jd/security/llmsec/core/util/SignUtil.java:36,62 |
| Guava RateLimiter 内存级限流 | safety/safety-api/.../service/RateLimitServiceImpl.java:7,30,69 |
| 识别结果缓存 15 分钟(user 且单条) | safety/safety-api/.../service/execute/FunctionExecutorImpl.java:247,253-254,275-287 |
| 配置 60s 轮询/变更判断/保底不丢配置 | safety/safety-api/.../service/DynamicConfigService.java:65,142-144,116-119 |
| DAG 主循环/超时检查/ignoreError | safety/safety-api/.../service/execute/FunctionExecutorImpl.java:289,297-299,312-323 |
| parallel 超时丢弃/线程池/归约 | safety/safety-api/.../service/execute/functions/ParallelFunction.java:87-92,130-136,142-172 |
| free_taxi 任务执行/会话锁 | safety/safety-api/.../service/task/TaskExecutorImpl.java:56-63,78-110 |
| AC 自动机敏感词 | safety/safety-skills/safety-keywords/.../service/data/SensitiveWordDetector.java:14-15 |
| 敏感词定时轮询重建 | safety/safety-skills/safety-keywords/.../service/data/SensitiveWordsManageServiceImpl.java:194 |
| 四种 match_type/黑白灰策略/QPS 字段 | safety/safety-admin/docs/tables.sql:9,10,41 |
| 7000 字截断 | safety/safety-api/.../config/GlobalConf.java:49 |
| 演示 DAG(阈值表/ignoreError) | docs/strategy_example.yml:23,65,94-95,107,114 |
| 官方 roadmap | README.md:346-353 |
| 脱敏插件机制(Rust/WASM,源码不在本仓库) | 引自 ../../maas-safe-doc/安全护栏/poc/网关脱敏插件实现原理分析-ai-data-masking-脱敏与还原.md(其中 ai_data_masking.rs:431-486、deny_word.rs:63-70 等坐标为该笔记核实结果) |
| 网关插件能力与问题清单 | 引自 ../../maas-safe-doc/安全护栏/poc/网关安全插件-1-基础功能验证.md、-2-高级能力验证以及存在的问题分析.md |
