Nginx sub_filter仅支持明文响应的纯字符串替换,需配gunzip on、sub_filter_types显式指定类型,不支持正则、大小写忽略和上下文判断,适用于代理出口轻量脱敏。

直接用 Nginx 的 sub_filter 指令就能在网关层做实时关键词过滤和脱敏,关键不是“能不能”,而是“怎么配才不漏、不崩、不慢”。它不碰请求体,只改响应体,轻量且生效快,适合代理出口统一处理。
明确适用边界:什么能干,什么不能碰
sub_filter 是纯字符串替换,不是正则引擎,也不解密、不解压——这些都得你手动铺路:
- 只处理明文响应,默认仅对
text/html生效;要改 JSON、JS、CSS,必须显式加sub_filter_types - 上游若返回 gzip 压缩内容,
sub_filter完全匹配不到,必须配gunzip on;(需启用ngx_http_gunzip_module)或让后端禁用 gzip - 大小写敏感,
"张三"不会匹配"张叁"或"zhangsan";真要忽略大小写,得换第三方模块或移交后端 - 不支持通配符、不支持上下文判断,比如无法只替换“手机号字段值”而放过“注释里的示例号码”
基础脱敏配置:从一条替换到多级控制
脱敏不是简单“找词替词”,顺序、范围、粒度都要卡准:
- 用
sub_filter_once off;确保全文所有匹配项都被处理,避免只掩掉第一个手机号 - 多个
sub_filter指令按书写顺序执行,建议把长词、高频词放前面,减少后续扫描开销 - 避免循环:比如
sub_filter "abc" "xyz"; sub_filter "xyz" "abc";会导致不可控结果 - 示例——统一脱敏测试标识与手机号:
location / {
proxy_pass https://origin;
gunzip on; # 必须加,应对 gzip 响应
sub_filter_types text/html application/json text/plain;
sub_filter_once off;
<pre class='brush:php;toolbar:false;'>sub_filter '<div class="env">TEST</div>' '';
sub_filter '13[0-9]{9}' '13****1234'; # ❌ 错误:sub_filter 不支持正则,这行无效
sub_filter '13812345678' '138****5678'; # ✅ 正确:只能逐个写死或靠后端预生成掩码
sub_filter '/admin/api/' '/[redacted]/';}
安全与合规提醒:别让脱敏变注入
同一套机制既能脱敏,也能注入——sub_filter 插 JS 脚本和删敏感词,技术上毫无区别:
- 向
</head>前插入监控脚本,和把<script src="/debug.js"></script>删掉,都是同一种能力 - 生产环境使用前,必须确认内容方授权;私自篡改第三方响应可能违反《网络安全法》及平台协议
- 防范被滥用:限制
sub_filter_types范围,禁用非必要类型;关闭未使用的 location 块中的 sub_filter;定期审计配置变更 - HTTPS 下端到端加密,中间网关无法解密响应体——所以实际中,sub_filter 注入多见于内网反向代理、测试环境或可控 CDN 边缘节点
替代与增强思路:什么时候该换方案
当需求超出 sub_filter 能力时,别硬撑:
- 需要正则、上下文感知、JSON Path 提取替换 → 改用
nginx-substitutions-filter模块(支持正则 + 多次替换) - 要对二进制、图片、PDF 做内容识别脱敏 → 必须下沉到应用层或专用 DLP 网关
- 敏感字段结构固定(如 API 返回的
"id_card": "110...")→ 后端用统一中间件做序列化前脱敏,更可靠、可审计 - 需要动态策略(按用户角色/地域切换脱敏强度)→ Nginx 难以承载,应由 API 网关(如 Kong、Apigee)或服务网格(Istio)处理

















