最近偿试做一个网站服务snsids.com,这个网站提供一个社交账号查询功能,即查询任意一个已知的社交账号,就可以获取这个用户其它的社交账号(用户自己提供)。为了防止恶意攻击,与其它所有网站一样,需要记录访客IP信息,本文重点要记录一下,为什么我的服务没有获取到客户端的真实IP。

![[Pasted image 20260412154352.png]]

当我登录后台查看访问记录时,发现访客IP几乎都一样,一开始以为是恶意批量扫描,但是仔细一看,发现URL都是常规URL,而不是探测后台的URL,我把IP地址放到百度里搜了一下,发现这个址是腾讯地址。我一下子就意识到,这个是腾讯CDN的地址。

我在开发程序的时候就考虑到会有反向代理的存在,当时查询了一下Gin的文档,需要调用SetTrustedProxies来设置可信反向代理。我的程序是跑在我的caddy后面的,所以我就直接把它设置成0.0.0.0/0表示全部信任。最初验证的时候,发现没有问题,是可以获取到客户端真实IP的。

但运行一段时间后觉得有两个问题,第一,服务器IP直接暴露了,这个肯定不安全。第二,服务器速度太慢了,能套上CDN就快多了。

所以我就直接在我的服务前面套了一层腾讯的EdgeOne,上面两个问题算是全部解决了,运行了几天也没发现有什么问题,速度还快了不少。直到今天才发现记录的IP都不对。

这就让我感觉奇怪了,最开始猜测是EdgeOne没有正确填写X-Forwarded-For字段,我用nc验证了一下请求头:

GET / HTTP/1.1
Host: snsids.com
...
Eo-Connecting-Ip: 121.237.92.*
Via: 1.1 Caddy
X-Forwarded-For: 43.152.134.* /*edgeone ip*/
X-Forwarded-Host: snsids.com
X-Forwarded-Proto: https
...

果然,X-Forwarded-For字段没有客户的的IP。是EdgeOne没有填写吗?我以为需要单独配置什么选项,但是找了一圈没找到配置的地方。

我突然想到可能是caddy的配置问题。于是搜了一下资料,发现caddy还真的需要配置trusted_proxies

{  
	servers {  
		trusted_proxies static 0.0.0.0/0  // 不安全,生产环境慎用
	}  
}

于是,我改了下配置,然后再测试,这次发现X-Forwarded-For的内容正常了:

GET / HTTP/1.1
Host: snsids.com
...
Eo-Connecting-Ip: 121.237.92.*
Via: 1.1 Caddy
X-Forwarded-For: 121.237.92.*, 43.152.134.* /*edgeone ip*/
X-Forwarded-Host: snsids.com
X-Forwarded-Proto: https
...

到这里就可以明确程序没有获取到真实客户端的IP,是因为caddy没有配置trusted_proxies导致EdgeOne传来的X-Forwarded-For内容就被丢弃了。

但是还有一个问题,你看我没有套EdgeOne之前也没有trusted_proxies,为什么这种情况可以获取到真实的IP?

理解X-Forwarded-For填写逻辑,这个问题就好解释了。在解释之前,先记住一个原则:

只要服务作为反向代理向后端转发请求,它就会把客户端 IP 追加到 X-Forwarded-For

Client ---> Caddy ---> SNSIDS
  1. 客户端以IP:121.237.92.* 直接连接Caddy。
  2. 因为Caddy没有配置trusted_proxies,所以客户端请求中X-Forwarded-For就被丢弃了(但是这种情况下,客户端也不会有X-Forwarded-For情况,所以无论是否配置trusted_proxies都不影响)。
  3. Caddy连接SNSIDS,因为客户端直接Caddy,所以Caddy把客户端的IP:121.237.92.*填入X-Forwarded-For,然后把请求发送给SNSIDS
  4. 因为SNSIDS配置了trusted_proxies,并信任所有源,所以Caddy传来的X-Forwarded-For内容被保留。
  5. 最后SNSIDS就可以通过X-Forwarded-For获取到真实的客户端IP地址。

再看看套了一层EdgeOne的逻辑:

Client ---> EdgeOne ---> Caddy ---> SNSIDS
  1. 客户端以 IP:121.237.92.* 直接连接 EdgeOne
  2. EdgeOne 连接 Caddy ,把客户端 IP:121.237.92.* 记录到 X-Forwarded-For 中,
  3. Caddy 收到 EdgeONe 发来的请求时有两种情况:
    1. 如果Caddy没有配置trusted_proxies,那么EdgeOne传来的X-Forwarded-For就会被丢弃
    2. 如果Caddy配置了trusted_proxies,那么X-Forwarded-For保持不变。
  4. Caddy连接SNSIDSCaddyEdgeOne 的IP追加到 X-Forwarded-For 中。
  5. 因为SNSIDS配置了trusted_proxies,并信任所有源,所以Caddy传来的X-Forwarded-For内容被保留。
  6. 最后SNSIDS就可以通过X-Forwarded-For获取到真实的客户端IP地址。