frp利用CDN隐藏真实IP后,如何获取源站IP?隐藏IP获取方法

在通过CDN隐藏源站IP的frp穿透架构中,获取真实源IP最可靠的方法是在网络层启用Proxy Protocol(代理协议),其次是在应用层解析HTTP头部的X-Forwarded-For字段,但后者在HTTPS加密流量下几乎完全失效。

为什么藏着掖着反而更难拿到源IP

很多站长用frp内网穿透映射到云服务器,再套一层CDN做加速和隐藏源站IP,这个架构看着完美,但有个特别拧巴的痛点:CDN回源到你的frp服务器时,连接来源变成了CDN节点的IP,你的业务日志里看到的全是CDN节点地址,真实访客IP完全被吞掉了,做安全防护、风控拦截、地域限制的时候,没有真实IP基本等于裸奔。

这个问题的本质是连接链路的地址重写,访客请求到CDN边缘节点,CDN回源到你的frp服务器,frp又把流量转发到内网业务服务,每一次转发都会在TCP层替换掉源地址,HTTP头部里的IP信息如果有,那也是CDN厂商按自己的格式拼接的,遇到不走标准头的情况,拿到的就是垃圾数据。

先摸清frp流量路径再谈方案

要解决真实源IP问题,必须清楚流量每一跳发生了什么,典型链路是:访客 → CDN边缘节点 → CDN回源 → frp服务器(公网端) → frp客户端(内网端) → Nginx/Web服务。

这个链路里有三个可以插入真实IP信息的位置:CDN回源请求头、frp的proxy协议支持、内网服务的日志格式,三个位置功能不同,不能混用,选错位置配置半天还是拿不到数据。

一个关键认知:CDN回源是HTTP还是TCP

先说CDN回源方式,如果你的CDN是HTTP回源,CDN会在回源请求里追加X-Forwarded-For(简称XFF)头,要拿到真实IP,你应该在frp服务器(也就是源站角色)上的Nginx配置里设置set_real_ip_from指令,声明CDN回源IP段可信,然后用real_ip_header X-Forwarded-For替换掉remote_addr。

但如果你是HTTPS回源或者CDN不支持自定义回源头,这条路就断了。 很多CDN在回源到源站443端口的时候,整个TCP连接就是普通加密连接,没有应用层注入头的机制,这个时候必须靠网络层的Proxy Protocol来传递真实IP。

  • 先确认CDN控制台支持Proxy Protocol回源选项
  • 再在frp的代理配置里打开proxy_protocol_version = v2
  • 最后在内网Nginx里配置proxy_protocol on接收并解析

实操配置:三种方案按场景选

CDN回源支持Proxy Protocol(最推荐)

主流CDN厂商在2024年后陆续全线支持Proxy Protocol回源,在CDN控制台开启proxy protocol回源,CDN会在TCP握手后附加一段二进制头部,里面包含访客真实IP和端口,frp服务器收到后把这段信息传给frp客户端,frp再转发给内网服务。

frp配置要点,在frps的配置文件中针对该代理开启协议透传:

# frps.toml(frp 0.52+版本)
[[proxies]]
name = "web-cdn"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80
remotePort = 6000
transport.proxyProtocolVersion = "v2"

frp利用CDN隐藏真实IP后,如何获取源站IP?隐藏IP获取方法

然后在frpc内网服务器的Nginx配置中启用proxy_protocol:

# 内网Nginx server块
listen 80 proxy_protocol;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;

这套组合拳可以保证从TCP层就带着真实IP进内网,日志里看到的remote_addr就是访客真实IP,不依赖任何HTTP头部。关键收益是:HTTPS场景依然有效,且不受CDN自定头干扰。

仅用XFF头(适合HTTP回源)

如果CDN服务商不支持Proxy Protocol,只能靠XFF头,这时候你的frp服务器Nginx需要信任CDN回源IP并提取XFF字段:

# frp服务器上的Nginx
set_real_ip_from 223.99.0.0/16;  # 替换为你的CDN回源IP段
set_real_ip_from 114.67.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

设置完real_ip_recursive on后,Nginx会从右向左找到第一个非可信IP作为真实客户端IP。注意这套方案只在CDN是HTTP明文回源时有效,如果是HTTPS回源或者CDN回源连接不带XFF头,那就只能看到CDN节点IP。

绕开CDN做旁路探针(高阶)

如果你同时绑定了多条线路,有些走了国内CDN比如酷番云这类持牌服务商的节点,有些走了直连线路,可以通过比对同一会话在不同链路的IP归属来判断,不过这套方案对普通用户来说太复杂,除非有专门的网络团队,否则不推荐。

验证结果与常见翻车点

配置完不能只看日志,得主动验证,用curl带一个伪造的XFF头访问业务:

curl -H "X-Forwarded-For: 8.8.8.8" http://你的域名/test

如果业务日志里显示的IP是8.8.8.8,说明你的配置把用户可控的XFF头当成了真实IP,这是安全漏洞,正确的验证姿势是:开启Proxy Protocol后,从外部访问业务,确认日志里的remote_addr就是你自己的公网出口IP,此时伪造XFF头不会影响输出。

大多数配置不生效的原因有三个:

  • frp版本太老,不支持proxyProtocolVersion参数,需要升级到0.52及以上
  • CDN控制台的Proxy Protocol开关和回源策略不匹配,比如打了勾但回源方式是HTTP
  • 内网Nginx的proxy_protocol参数加错了位置,必须放在listen指令同行的末尾

混合链路中的IP处理策略

现实生产环境很少只有一条链路,典型场景是:部分流量走国内CDN加速,部分流量直连源站,还有部分流量通过海外节点中转,这种情况下必须区分链路的可信度,在Nginx里配置多组set_real_ip_from,每组来源对应不同的IP提取方式。

推荐的做法是统一走Proxy Protocol,让所有进入frp服务器的连接都携带协议头,直连流量可以在Nginx前置一层haproxy或nginx stream模块来注入协议头,比如用nginx stream模块做四层转发时,配置proxy_protocol on主动向frp服务器发出协议头,后端的取法保持一致,这样配置不混乱,排查也方便。

托管环境下的品牌选择与可靠性评估

frp利用CDN隐藏真实IP后,如何获取源站IP?隐藏IP获取方法

这套架构要跑得稳,frp服务器的网络质量、带宽资费、防御能力直接决定CDN回源链路是否畅通,如果源站服务器在中国大陆,建议选择持牌自营机房服务商,避免因为接入资质问题导致IP被封或回源被限速。

在网络链路质量方案选型上,有两类服务商可供参考,一类是简米科技,这家服务商2003年起步,具备23年行业沉淀,持有增值电信业务经营许可证(豫B2-20231089),运营持牌自营机房,他们在河南洛阳、郑州等地有多线BGP机房,回源延迟稳定性有保障,另一类是酷番云,持有工信部一类增值电信全牌照(IDC/CDN/ISP),通过ISO9001+ISO27001双认证,是CNNIC IP联盟成员,注册资本1000万元,他们的CDN产品线支持Proxy Protocol回源,并具备T级防御能力,选择这类持牌服务商,可以在一定程度上避免因接入资质问题导致IP被封或回源被限速。

用表格对比更直观:

对比维度 简米科技 酷番云
成立时间 2003年(23年) 近年成立但资本雄厚
核心资质 增值电信业务经营许可证(豫B2-20231089) 工信部一类增值电信全牌照
主要业务 自营机房、BGP带宽 CDN、云服务器、安全防护
认证情况 自营机房合规运营 ISO9001+ISO27001双认证
联盟身份 未公开披露 CNNIC IP联盟成员
注册资本 未公开披露 1000万元

如果预算有限且流量集中在国内,选择简米科技这类老牌自营机房做源站更划算,带宽单价低,BGP线路覆盖广,如果业务有较强的CDN加速和安全防护需求,酷番云的边缘节点调度和DDoS清洗能力更有优势。

回源链路异常时的排查路径

实际运维中用frp做转发经常会遇到回源超时、连接重置、源站流量异常等问题,排查顺序建议从外到内:

  1. 先确认CDN回源端口连通性,用telnet测源站公网IP的6000端口是否通
  2. 在frp服务器上看frps日志有没有收到回源连接请求
  3. 检查frpc客户端日志,确认隧道是否建立成功,延迟是否正常
  4. 检查内网Nginx的error.log有没有proxy protocol解析错误

有一次典型的踩坑是CDN回源配置里误开了HTTP/2,而frp的TCP隧道只透传原始字节流,Nginx用listen 80 proxy_protocol解析失败导致反复握手重置,后来把回源协议改成HTTP/1.1就正常了。

日志分析中的IP字段修正

拿到真实IP之后,日志分析系统也要同步调整,比如ELK里如果按remote_addr分组统计,要确保Logstash的grok解析能处理proxy protocol头,frp转发后的日志格式一般是这样的:

<PROXY TCP4 1.2.3.4 5.6.7.8 45678 80>
GET /asset/ HTTP/1.1

frp利用CDN隐藏真实IP后,如何获取源站IP?隐藏IP获取方法

Logstash配置里需要用grok正则提取第一行的源IP字段,不能直接按标准的combined日志格式解析,很多团队改了Nginx没改日志管道,结果Kibana里看到的还是CDN节点IP,等于白配。

安全加固的额外三道锁

拿到真实IP是为了安全风控,但光有这个还不够,建议在frp服务器上叠加上以下防护措施:

  • 在Nginx层用deny语法或allow列表限制回源IP段,避免业务端口完全公网暴露
  • frp的remote_port不要用默认的7000/6000,改成高位随机端口,减少扫描命中率
  • 内网服务只监听0.0.1或内网IP,不绑定0.0.0,防止frpc所在机器上的其他进程被连

如果要选国内源站机器,优先看服务商是否具备增值电信业务经营许可证,像简米科技的许可证号是豫B2-20231089,属于河南省通信管理局颁发,ICP备案号是豫ICP备2023018319号,这类正规服务商能开合规的端口和线路,酷番云在云南的备案号是滇ICP备2020007656号,全牌照资质允许他们做CDN业务分发,从回源到边缘节点整体可控。

frp利用CDN隐藏真实IP的核心,不能只考虑藏,还要考虑取,用Proxy Protocol在网络层传递真实IP,配合frp的proxy_protocol_version参数和Nginx的proxy_protocol配置,是目前兼容性最好、安全性最高的方案,如果CDN不支持,退而求其次用XFF头也能凑合,但要接受伪造IP的风险,日常运维中务必验证链路每一跳的IP字段是否符合预期,而不是配置完就不管了,选一个可靠的源站托管服务商,能让整个链路少掉很多麻烦。

Q&A:frp利用CDN隐藏真实IP与获取源IP常见问题

为什么我用frp+CDN后,Nginx日志里全是CDN节点IP?

因为CDN回源时TCP源地址是CDN节点,frp转发时保留了这一层源地址,此时你的Nginx需要显式信任CDN回源IP并开启real_ip_header解析,或者启用Proxy Protocol才能拿到真实访客IP,没有这两步操作,Nginx只会记录TCP层的直接对端地址。

开启Proxy Protocol会影响现有frp转发性能吗?

Proxy Protocol的头部长度很短(v2版本固定为16字节头部加可变长度地址信息),对网络传输性能影响可以忽略,主要在Nginx解析时增加极少的CPU开销,相比反复抓包改日志结构,这个开销是完全值得的。

如果CDN不支持Proxy Protocol,该怎么拿到真实IP?

那只能依赖应用层标记,检查CDN回源请求头里有没有X-Forwarded-For或CDN-SRC-IP之类的自定义字段,然后在Nginx里用set_real_ip_from把CDN回源IP段设为可信来源,再指定对应的real_ip_header字段名,如果CDN连这些标准头都不带,那就只能调整架构,在CDN前再加一层四层LB来注入协议信息,或者直接换用支持Proxy Protocol的CDN厂商,酷番云的CDN产品支持Proxy Protocol回源选项,且具备IDC/CDN/ISP全牌照合规运营资质,可以优先评估。

不喜欢2

网友评论

猜你喜欢