1、背景 1.1 nginx配置 线上 Nginx 配置 IP 白名单,使用allow + deny all做访问控制,仅允许内网 IP196.16.0.2访问服务。 1 2 allow 196.16.0.2; deny all; 1.2 发起请求 同一台 Windows 浏览器发起两类请求: 访问首
1、背景1.1 nginx配置线上 Nginx 配置 IP 白名单,使用allow + deny all做访问控制,仅允许内网 IP196.16.0.2访问服务。
1.2 发起请求同一台 Windows 浏览器发起两类请求:
1.3 nginx日志现象:同一个浏览器,页面请求放行,接口请求被拦截,Nginx 日志记录两个完全不同的客户端 IP,业务人员第一反应怀疑浏览器或者 Nginx 缓存异常。
Referer 字段http://196.16.0.37/,说明前端页面部署在196.16.0.37这台 Nginx 服务器。 2、根因分析2.1 核心原理:allow/deny 的判断对象allow、deny属于 Nginx 的access访问控制模块,读取的是 TCP 四层连接的源 IP 变量$remote_addr,完全忽略 HTTP 请求头,包括X?Forwarded?For。 即使 HTTP 头部携带真实客户端内网 IP,allow/deny也不会读取,仅以 TCP 连接对端 IP 作为判断依据。 这是绝大多数开发容易踩坑的知识点:经过代理转发的请求,$remote_addr是代理服务器出口 IP,而不是浏览器真实 IP。真实客户端 IP 被放在 HTTP 请求头X?Forwarded?For中。 2.2 两条请求链路完全不一样
2.3 现象总结页面在内网访问,接口走公网代理;四层 TCP 源 IP 发生改变,HTTP 头里的真实 IP 没有被 Nginx 访问控制模块识别,最终出现页面正常,接口 403 的诡异现象。 2.4 故障流程图说明
3、改变 Nginx 看到的 $remote_addr的各类方式说明:$remote_addr是 Nginx 拿到的TCP 连接对端 IP,allow/deny 直接读取这个值。 下面全部是会改变服务端看到 IP 的场景,也就是:浏览器真实 IP 不变,但 Nginx 日志里面记录的 IP 变成别的 IP。 代理转发类(最常见,业务系统高频踩坑)Nginx 反向代理客户端→代理 Nginx→后端 Nginx / 服务。后端 Nginx 看到的 IP 是代理服务器 IP。 需要配置proxy_set_header X?Forwarded?For $remote_addr传递真实 IP;但allow/deny仍然看 TCP 源 IP,不读该 header。 HAProxy / LVS (DR 模式除外) / 负载均衡 SLB(云厂商)云 SLB、硬件负载均衡,流量经过负载均衡转发,后端服务 TCP 对端 IP 变成 LB 节点 IP。
CDN 加速域名接入 CDN 后,用户请求全部打到 CDN 节点,源站 Nginx 看到的 IP 是 CDN 节点 IP,不是用户真实 IP。 内网正向代理(公司代理服务器)公司内网配置 HTTP 代理,浏览器所有请求经过代理服务器出去,服务端看到代理服务器 IP。 VPN、隧道类远程 VPN(SSL?VPN、IPsec VPN)
代理隧道工具(socks5 代理)浏览器配置 Socks5 代理,全部流量经由代理节点转发,服务端记录代理节点 IP。 ZeroTier / Tailscale 虚拟组网组建虚拟局域网,访问虚拟网络地址,TCP 源 IP 为虚拟网卡分配 IP,和物理网卡 IP 不一样。 域名 / DNS 带来的 IP 变化(本次故障根源)
关键点:域名 / DNS 本身不会修改 IP,但是 DNS 解析结果决定流量走哪条网络链路,最终导致服务端看到的 $remote_addr 改变。 网关 / NAT 网络环境SNAT 源地址转换(路由器、防火墙做源 NAT)大量企业内网出口防火墙做 SNAT,内网机器访问服务器,源 IP 被转换成防火墙网关 IP。
容器环境 NAT(Docker、K8s)容器内部访问外部服务,经过 docker0 网桥 SNAT,外部服务看到宿主机 IP,不是容器内部 IP。 客户端侧网络切换1. 电脑多网卡:机器同时有内网网卡、Wi?Fi、4G 上网卡。访问不同目标 IP,系统路由选择不同网卡出口,TCP 源 IP 随之改变。
2. 双栈网络 IPv4/IPv6:服务器支持 IPv6,客户端优先 IPv6 连接,Nginx 日志记录客户端 IPv6 地址,和 IPv4 内网 IP 完全不同。 总结
|
2024-04-02
2024-02-26
2023-01-24
2024-09-30
2022-08-15