Nginx 动态安全头应优先使用 map 指令实现:通过 map 匹配可信 Origin 实现 CORS 白名单、映射 $request_id 生成 CSP nonce、结合 geo 划分网络区域实施灰度安全策略,全部在 http 块顶层定义,轻量稳定无副作用。

直接用 add_header 静态写死安全头,既不灵活也不安全。真正可靠的动态防护,得靠 map 指令提前做判断,再把结果注入响应头——它不执行逻辑,只做映射,轻量、稳定、无副作用。
用 map 匹配可信 Origin 实现动态 CORS
浏览器跨域请求带 Origin 头,但不能无条件回传。用 map 做白名单校验最稳妥:
- 在
http块顶部定义映射:
default "";
"~^https?://(localhost|127\.0\.0\.1|dev\.example\.com)(:[0-9]+)?$" "$http_origin";
}
- 匹配成功时
$cors_origin等于原始Origin,否则为空字符串 - 后续在
location中用add_header Access-Control-Allow-Origin $cors_origin always,空值不生效,不暴露头,更安全 - 避免硬编码域名,开发、测试、预发环境可共用一套配置
用 request_id 生成动态 CSP nonce
内联脚本需唯一 nonce 才能通过 CSP 校验,$request_id 是 Nginx 原生提供的 UUID 级唯一标识,无需额外模块:
- 先映射出可用于 CSP 的 nonce 值(去除短横线,适配 base64):
default "";
"~^(.{8})(.{4})(.{4})" "$1$2$3";
}
- 在响应头中注入:
- 前端 HTML 中对应 script 标签写
nonce="xxx",每次请求值不同,攻击者无法复用 - 不用改应用代码,不依赖后端生成,Nginx 层完成闭环
用 geo + map 组合实现灰度级安全策略
不同用户群体或网络区域,安全强度可以差异化。比如内部 IP 允许调试头,公网则屏蔽:
- 先用
geo划分网络段:
default 0;
10.0.0.0/8 1;
192.168.0.0/16 1;
}
- 再用
map将状态转为响应头内容:
0 "";
1 "X-Debug: enabled; X-Backend: $upstream_addr";
}
- 最后统一注入:
add_header $debug_headers always - 公网请求看不到调试信息,内网运维可快速定位问题
- 比 if 判断更高效,适合高频路径
注意事项与避坑点
map 必须定义在 http 块顶层,不能放在 server 或 location 内;变量名不能重复;正则匹配注意转义点和括号;所有用于 add_header 的变量必须加 always 参数,否则 4xx/5xx 或 OPTIONS 响应不会携带。











