nginx中用valid_referers配合正则实现子域名白名单,需匹配完整referer url(含协议、端口、路径),正确书写pcre正则并规避漏协议、未转义点号、缺锚定等常见错误,再结合$invalid_referer变量与if判断返回403。

在 Nginx 中用 valid_referers 指令配合正则表达式实现子域名白名单,关键在于正确书写 PCRE 兼容的正则,并注意匹配逻辑和常见陷阱。
正则写法要覆盖所有合法子域名
Nginx 的 valid_referers 支持正则(以 ~ 开头),但需注意:它匹配的是整个 Referer 字符串(含协议、端口、路径),不是仅主机名。所以不能只写 ~^example\.com$,而应匹配完整 URL 结构。
例如,允许 https://a.example.com、http://b.example.com:8080/path、https://shop.example.com,可这样写:
valid_referers ~^https?://([a-z0-9-]+\.)*example\.com(:[0-9]+)?/;- 说明:
https?匹配 http 或 https;([a-z0-9-]+\.)*匹配零个或多个子域名段(如api.、cdn.、www.);example\.com是主域;(:[0-9]+)?可选端口;结尾的/是为了确保匹配到路径起始,避免误匹配example.com.attacker.com这类恶意域名。
避免常见匹配错误
以下写法容易出问题,需规避:
- 漏掉协议和斜杠 ——
~example\.com会匹配任意位置出现example.com的字符串(如http://evil.com?referer=badexample.com); - 未转义点号 ——
~example.com中的.会被当作正则通配符,匹配任意字符; - 缺少锚定 —— 不加
^和/(或$)会导致部分匹配,安全性下降; - 忽略大小写 —— 默认区分大小写,如需兼容大写 host,加
~*前缀(如~*^https?://([a-z0-9-]+\.)*example\.com)。
结合变量与 if 判断做拦截
valid_referers 本身不直接拦截,它把匹配结果存入内置变量 $invalid_referer(值为 1 表示不匹配白名单)。需配合 if 使用:
valid_referers ~^https?://([a-z0-9-]+\.)*example\.com(:[0-9]+)?/;if ($invalid_referer) { return 403; }- 注意:
if在 location 中使用是安全的,但不要放在 server 级别顶层或与重写逻辑混用,以防意外行为。
测试与调试建议
上线前务必验证正则是否符合预期:
- 用
curl -H "Referer: https://shop.example.com/page" http://your.site/asset.jpg测试放行; - 用
curl -H "Referer: https://evil.com?domain=example.com" http://your.site/asset.jpg测试拦截; - 开启 Nginx 错误日志
error_log /path/to/error.log notice;,Referer 匹配失败时会在日志中提示“access forbidden by rule”,辅助排查。











