必须在Nginx的location块中、proxy_pass前配置allow/deny实现IP层白名单,因WebSocket握手是HTTP请求,可在该阶段用真实IP严格控制;不可依赖Origin头、Referer、stream模块或if判断。

在 WebSocket 代理中配置严格的来源白名单,不能依赖 HTTP 层的 allow/deny(它对 WebSocket 握手请求无效),也不能靠前端传参或 Referer 头做判断——因为 WebSocket 的 Origin 头可被客户端伪造,且浏览器在 wss 场景下会强制校验 TLS 和域名一致性。真正可行的严格白名单,必须落在 Nginx 的 HTTP 请求阶段,在 WebSocket 升级前完成 IP 层过滤。
必须用 http 块中的 location + allow/deny 控制入口
WebSocket 连接建立的第一步仍是标准 HTTP 请求(GET /ws),Nginx 在这个阶段完全能识别客户端真实 IP,并执行访问控制:
- 规则必须写在
location块内,且放在proxy_pass之前 - 使用
allow列出可信网段(如192.168.10.0/24、2001:db8::/32),最后必须加deny all - 确保
real_ip_header和set_real_ip_from已正确配置(若前端有 CDN 或 LB),否则$remote_addr可能是代理 IP 而非真实来源
避免常见误操作
以下做法无法实现“严格”白名单,慎用:
- 在 stream 模块里配 allow/deny:stream 是 TCP 层代理,不解析 HTTP 头,无法识别 WebSocket 握手请求,也不支持 Origin 或 Host 判断
- 只靠 proxy_set_header Origin $http_origin:Origin 是客户端发送的字符串,后端即使校验也无法防止 IP 伪造;且 Nginx 本身不校验 Origin
- 用 if ($http_origin !~ ...) { return 403; }:if 在 location 中限制力弱,且可能因指令执行顺序导致绕过;更严重的是,某些 WebSocket 客户端(如部分浏览器扩展或测试工具)可能不带 Origin 头,造成误拦
生产环境推荐组合策略
单靠 IP 白名单还不够健壮,建议叠加一层轻量级校验:
- 在 location 中先做 IP 白名单(基础防线)
- 通过
proxy_set_header X-Forwarded-For $remote_addr把真实 IP 透传给后端 - 后端服务在校验 WebSocket 握手时,同时检查
X-Forwarded-For是否在预设白名单内(双重校验,防 Nginx 配置遗漏) - 如需动态管理,可用
geo指令预加载 IP 段变量,再配合map或if做条件跳转(仅限 Nginx ≥ 1.19)
一个完整可用的配置示例
假设只允许公司办公网(10.20.0.0/16)和运维跳板机(172.16.5.100)建立 WebSocket 连接:
location /ws/ {
# 白名单控制(严格生效于握手请求)
allow 10.20.0.0/16;
allow 172.16.5.100;
deny all;
<pre class='brush:php;toolbar:false;'>proxy_pass http://ws_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 86400;}


















