news 2026/9/16 22:30:18

Higress AI 数据脱敏(ai-data-masking)插件:敏感词拦截与替换实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Higress AI 数据脱敏(ai-data-masking)插件:敏感词拦截与替换实战指南

Higress AI 数据脱敏(ai-data-masking)插件:敏感词拦截与替换实战指南

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

Higress 的ai-data-masking(AI 数据脱敏)插件是一款运行在认证阶段(优先级 991)的 WASM 插件,用于对 AI 网关请求/响应中的敏感信息进行拦截脱敏替换,在保证"敏感数据不出域"的前提下让大模型正常参与业务推理。阅读本文后,你将掌握该插件的处理数据范围、全部配置字段与默认值、基于 GROK/正则的替换规则设计,以及流式(SSE)场景下的还原机制与已知限制,并能在自己的 Higress 网关上直接复现文中的完整配置示例。

该插件源码位于 plugins/wasm-rust/extensions/ai-data-masking,核心实现集中在 src/ai_data_masking.rs,配套 README.md 与 README_EN.md 提供了中英文配置参考。

一、功能说明与处理数据范围

插件核心能力只有两件事:对请求/返回中的敏感词进行拦截、替换

1.1 处理数据范围(三种粒度)

范围说明
openai 协议请求/返回中的对话内容(messages[*].contentreasoning_content
jsonpath只处理通过 JSONPath 指定的字段
raw处理整个请求/返回 body(非 JSON 场景)

三种模式并非互斥,配置项deny_openaideny_jsonpathdeny_raw可同时开启,插件按 openai → jsonpath → raw 的顺序逐级处理。

从源码实现看,请求体处理逻辑位于 on_http_request_complete_body:插件首先尝试将 body 反序列化为 JSON;若deny_openai开启且能解析出 OpenAI 协议结构(stream字段 +messages数组),则标记is_openai = true并逐条检查contentreasoning_content;否则继续尝试 jsonpath 命中字段;最后才进入 raw 整包处理。响应方向对应 on_http_response_complete_body,同样按 openai 与 raw 两条路径执行拦截与还原。

1.2 敏感词拦截

  • 在数据处理范围内命中敏感词时直接拦截,返回预设错误信息;
  • 支持系统内置敏感词库自定义敏感词deny_words)两种来源。

内置词库通过rust-embed在编译期打包进 WASM 产物,数据文件为 res/sensitive_word_dict.txt(约 6.4 万行),由 src/deny_word.rs 的DenyWord::system()加载。词库数据来源为开源项目 houbb/sensitive-word-data。

需要特别注意的是匹配算法:DenyWord::check()使用jieba 分词后逐个词在HashSet中精确比对(见 deny_word.rs),因此deny_words必须配置为单个单词;英文多词短语(如hello world)由于分词粒度问题可能无法匹配。

1.3 敏感词替换

  • 将请求数据中出现的敏感词替换为脱敏字符串后再传给后端服务,保证敏感数据不出域
  • 部分脱敏数据在后端服务返回后可自动还原
  • 自定义规则支持标准正则GROK 规则,替换字符串支持正则变量(如$domain)。

替换规则由replace_roles数组定义,每条规则包含regex(支持 GROK 语法)、typereplacehash)、restore(是否还原)、value(替换值)。其核心实现位于 replace_request_msg:

  • 纯替换且不还原(replace+restore=false):直接对全文做replace_all
  • 需要还原或 hash 的场景:逐条正则匹配后,用HMAC-SHA256对原文计算十六进制摘要(hash类型),或按规则生成替换值,并把「脱敏值 → 原始值」的映射写入请求级mask_map(见 ai_data_masking.rs);
  • 响应阶段遍历mask_map,把大模型返回内容中的脱敏值替换回原始值后再转发给用户。

由此实现"出域前脱敏、回程时还原",示例见第五节。

二、运行属性

  • 插件执行阶段:认证阶段(Authentication Phase)
  • 插件执行优先级991

这意味着 ai-data-masking 在 Higress 的认证环节即开始生效,早于后续路由与转发逻辑,保证敏感词在被转发到后端前就已完成拦截或脱敏。插件基于 proxy-wasm 的RootContext/HttpContext模型实现,在 ai_data_masking.rs 通过proxy_wasm::main!注册入口,并复用了 Higress WASM Rust SDK 的RuleMatcher规则匹配框架(支持按路由/域名粒度下发不同配置)。

三、配置字段详解

名称数据类型默认值描述
deny_openaibooltrue对 OpenAI 协议进行拦截
deny_jsonpathstring[]对指定 jsonpath 字段拦截
deny_rawboolfalse对原始 body 拦截
system_denyboolfalse开启内置拦截规则
deny_codeint200拦截时的 HTTP 状态码
deny_messagestring提问或回答中包含敏感词,已被屏蔽拦截时 OpenAI 协议返回的 AI 消息
deny_raw_messagestring{"errmsg":"提问或回答中包含敏感词,已被屏蔽"}非 openai 拦截时返回的内容
deny_content_typestringapplication/json非 openai 拦截时返回的 Content-Type 头
deny_wordsarray of string[]自定义敏感词列表
replace_rolesarray-自定义敏感词正则替换规则
replace_roles.regexstring-规则正则(支持内置 GROK 规则)
replace_roles.type[replace, hash]-替换类型
replace_roles.restoreboolfalse是否在响应中还原
replace_roles.valuestring-替换值(支持正则变量)

上述默认值均与源码中的反序列化逻辑一一对应(见 ai_data_masking.rs 的default_deny_*系列函数),其中deny_code在源码中被解析为u16类型,配置时注意取值范围。

配置解析阶段值得一提的细节:

  • regex字段由 deserialize_regexp 完成反序列化:配置加载时先尝试把内容当作GROK 模式编译,失败则回退为标准正则编译,两者都不合法时直接报配置错误;
  • deny_jsonpath由 deserialize_jsonpath 解析为jsonpath_rust::JsonPath对象,非法路径会在配置阶段报错;
  • type字段仅接受replace/hash两个取值(deserialize_type)。

四、完整配置示例

system_deny: true deny_openai: true deny_jsonpath: - "$.messages[*].content" deny_raw: true deny_code: 200 deny_message: "提问或回答中包含敏感词,已被屏蔽" deny_raw_message: "{\"errmsg\":\"提问或回答中包含敏感词,已被屏蔽\"}" deny_content_type: "application/json" deny_words: - "自定义敏感词1" - "自定义敏感词2" replace_roles: - regex: "%{MOBILE}" type: "replace" value: "****" # 手机号 13800138000 -> **** - regex: "%{EMAILLOCALPART}@%{HOSTNAME:domain}" type: "replace" restore: true value: "****@$domain" # 电子邮箱 admin@gmail.com -> ****@gmail.com - regex: "%{IP}" type: "replace" restore: true value: "***.***.***.***" # ip 192.168.0.1 -> ***.***.***.*** - regex: "%{IDCARD}" type: "replace" value: "****" # 身份证号 110000000000000000 -> **** - regex: "sk-[0-9a-zA-Z]*" restore: true type: "hash" # hash sk-12345 -> 9cb495455da32f41567dab1d07f1973d # hash后的值提供给大模型,从大模型返回的数据中会将hash值还原为原始值

4.1 内置 GROK 规则说明

示例中出现的%{MOBILE}%{EMAILLOCALPART}%{HOSTNAME}%{IP}%{IDCARD}均来自 GROK 内置规则。源码在 ai_data_masking.rs 中额外注册了两个系统模式:

static SYSTEM_PATTERNS: &[(&str, &str)] = &[ ("MOBILE", r#"\d{8,11}"#), ("IDCARD", r#"\d{17}[0-9xX]|\d{15}"#), ];

GROK 模式展开采用迭代替换算法(grok_to_pattern):先解析%{PATTERN:alias}语法,将命名的 GROK 模式逐层展开为最终正则,并支持通过:alias给捕获组命名——这正是邮箱规则中%{HOSTNAME:domain}搭配替换值****@$domain实现"保留域名"替换的底层机制。

4.2 拦截响应形态

命中敏感词后的响应行为在 deny 中实现,与is_openaistream状态相关:

  • 请求方向拦截:直接send_http_response,返回deny_code状态码与deny_message(OpenAI 场景会包装为 choices 结构);
  • 非 openai / raw 拦截:返回deny_raw_message内容与deny_content_type头;
  • 响应方向拦截(流式):置空响应体并Continue,避免向用户输出不完整内容。

五、敏感词替换样例(还原链路演示)

5.1 用户请求内容

请将curl http://172.20.5.14/api/openai/v1/chat/completions -H "Authorization: sk-12345" -H "Auth: test@gmail.com"改成post方式

5.2 处理后请求大模型内容

curl http://***.***.***.***/api/openai/v1/chat/completions -H "Authorization: 48a7e98a91d93896d8dac522c5853948" -H "Auth: ****@gmail.com"改成post方式

可以看到三类处理同时生效:

  • 172.20.5.14(IP)→***.***.***.***,且restore: true会登记还原映射;
  • sk-12345(API Key,hash类型)→48a7e98a91d93896d8dac522c5853948(HMAC-SHA256 摘要);
  • test@gmail.com(邮箱)→****@gmail.com(通过 GROK 别名变量保留域名)。

5.3 大模型返回内容

大模型在完全不知晓原始敏感值的情况下完成改写任务:

curl -X POST \ -H "Authorization: 48a7e98a91d93896d8dac522c5853948" \ -H "Auth: ****@gmail.com" \ -H "Content-Type: application/json" \ -d '{"key":"value"}' \ http://***.***.***.***/api/openai/v1/chat/completions

5.4 处理后返回用户内容

插件在响应阶段根据mask_map将脱敏值还原为原始值,用户拿到的结果与原始请求完全一致:

curl -X POST \ -H "Authorization: sk-12345" \ -H "Auth: test@gmail.com" \ -H "Content-Type: application/json" \ -d '{"key":"value"}' \ http://172.20.5.14/api/openai/v1/chat/completions

还原逻辑对应响应处理代码中的mask_map.iter()遍历替换(ai_data_masking.rs):先检查响应内容是否含敏感词(命中则拦截),再把脱敏值替换回原始值。

六、流式(SSE)模式下的实现与限制

OpenAI 流式响应以data:前缀的 SSE chunk 形式下发,脱敏/还原必须跨 chunk 拼接处理。插件通过 msg_win_openai.rs 的MsgWindow实现:使用higress_wasm_rust::event_stream::EventStream解析 SSE 事件流,按choices[*].index维护独立的MessageWindowOpenAi滑动窗口,逐 chunk 累积文本后执行敏感词检查与还原替换,并将usage字段通过 number_merge.rs 的NumberMerge做跨 chunk 累加合并,保证重写后的流式响应在结构与统计字段上依然完整合法。非 OpenAI 流则退化为 msg_window.rs 的通用字节窗口。

该窗口模块自带单元测试(msg_win_openai.rs):使用 test/raw_message.txt 中的真实流式报文逐行喂入,验证contentreasoning_content跨 chunk 替换后能无损还原拼接结果。

6.1 相关说明(已知限制)

  • 流模式中,如果脱敏后的词被多个 chunk 拆分,可能无法进行还原
  • 流模式中,如果敏感词被多个 chunk 拆分,可能会有敏感词的一部分返回给用户的情况
  • GROK 内置规则列表可参考阿里云 SLS 用户指南的 grok-patterns 文档;
  • 内置敏感词库数据来源为 houbb/sensitive-word-data 项目;
  • 由于敏感词列表是在文本分词后进行匹配的,请将deny_words设置为单个单词,英文多单词情况(如hello world)可能无法匹配。

这四点限制均与滑动窗口的实现边界直接相关——窗口重叠区(char_window_size * 2/byte_window_size * 2,见 on_http_response_body)的设计正是为了尽量降低跨 chunk 拆词概率,但仍无法覆盖极端拆分场景,生产使用时建议将脱敏词设计为不易被截断的形态。

七、如何接入与验证

  • 该插件为 Higress 的 WASM Rust 插件,构建产物为 cdylib(见 Cargo.toml),当前版本记录在 VERSION(2.0.2)。完整构建与发布流程可参考 plugins/wasm-rust/Makefile 及 plugins/wasm-rust/README.md;
  • 在 Higress 中通过 WasmPlugin CRD 将插件挂载到网关或指定域名,并将上文配置示例写入defaultConfig即可生效;插件声明在认证阶段、优先级 991,会先于普通路由规则执行;
  • 验证时可先开启system_deny: true观察内置词库命中行为,再按第四节示例配置替换规则,并用第五节样例中的 curl 请求做端到端对比:比对发往大模型的请求体(应已脱敏)与最终返回用户的内容(应已还原)。

通过合理组合deny_openai/deny_jsonpath/deny_raw三种作用域、replace/hash两种替换类型以及restore还原开关,ai-data-masking 插件可以在 AI 网关链路上实现"敏感数据不出域、业务功能不降级"的合规目标,是 AI 网关数据安全治理中一个可直接落地的方案。

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 22:26:49

智能体技能工程体系:TypeScript + Nx + 语义化发布实战

1. 项目概述:这不是一个“技能库”,而是一套可复用、可验证、可演进的智能体能力工程体系你搜“agent-skills”时,看到的多半是零散的 GitHub 仓库、某篇博客里几行代码示例,或是面试题里一句“请手写一个工具调用函数”。但真正做…

作者头像 李华
网站建设 2026/9/16 22:23:13

微信小程序点餐系统毕设源码(Spring Boot+MySQL)

简介:这是一套面向计算机专业本科生的微信点餐系统毕业设计/课程设计完整源码,适用于小程序开发入门到进阶实践,解决从菜单展示、用户下单、订单管理到后台数据交互的一站式学习需求。资源共1285个文件,涵盖138个Vue页面组件&…

作者头像 李华
网站建设 2026/9/16 22:20:28

从LS到MMSE:信道估计入门与干扰管理视角的深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华