应先通过logstash规则准确提取真实客户端ip再做geoip解析:从右往左遍历x-forwarded-for列表,剔除可信代理ip和私有地址,取首个不可信公网ip;若无则回退remote_addr,并写入client字段供geoip插件使用。

直接用 Logstash 的 geoip 插件无法识别多层代理后的原始客户端 IP,必须先通过规则准确提取真实 IP,再做地理信息解析。核心在于:区分可信代理、跳过内网段、保留最外层不可信 IP 作为 fallback。
识别并剥离可信代理链(X-Forwarded-For)
Nginx 日志中若记录了 $http_x_forwarded_for,该字段通常是逗号分隔的 IP 链,如 "203.0.113.5, 192.168.1.10, 172.16.0.20"。不能直接取第一个,需结合 Nginx 配置中定义的可信代理列表(如 CDN 或负载均衡器 IP 段)逐层剥离。
- 在 Logstash filter 中用 dissect 或 grok 先提取
x_forwarded_for字段值 - 用 ruby 过滤器遍历 IP 列表,从右往左比对是否属于已知可信网段(如
["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "203.0.113.0/24"]) - 遇到第一个不在可信列表中的 IP,即为真实客户端 IP;若全部可信,则回退到
remote_addr
处理嵌套代理与私有地址混杂场景
常见异常情况包括:XFF 被伪造、私有 IP 出现在链首、多个公网 IP 连续出现。需设定安全兜底逻辑:
- 过滤掉所有 RFC1918 私有地址(
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)和本地回环(127.0.0.0/8) - 若清洗后为空,使用
remote_addr—— 但需确认该字段未被前置代理覆盖(可通过set_real_ip_from配置保证) - 添加字段标记清洗状态,例如
client_ip_source: "xff_cleaned"或"fallback_remote_addr",便于后续排查
结构化输出并衔接 GeoIP 查询
提取出真实客户端 IP 后,必须将其写入固定字段(如 [client][ip]),才能被 geoip 插件识别:
- 确保字段类型为 string(避免数字型 IP 被误解析)
- 在 geoip 插件配置中指定
source => "[client][ip]",并启用country_code2、region_name、city_name等常用字段 - 添加
if [client][ip] =~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/ { ... }条件判断,防止非法 IP 触发 geoip 异常
验证与调试技巧
规则上线前务必验证各种拓扑组合:
- 构造测试日志行,覆盖典型链路:
"203.0.113.5, 192.168.1.10"(CDN + 内网 LB)、"192.168.1.5"(直连)、"127.0.0.1, 203.0.113.6"(伪造) - 用 stdout { codec => rubydebug } 查看中间字段变化,重点关注
x_forwarded_for、remote_addr、[client][ip] - 开启 Logstash slowlog,定位 ruby 脚本性能瓶颈(尤其 IP 段匹配建议预编译正则或用 CIDR 库)











