最近偿试做一个网站服务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
- 客户端以
IP:121.237.92.*直接连接Caddy。 - 因为
Caddy没有配置trusted_proxies,所以客户端请求中X-Forwarded-For就被丢弃了(但是这种情况下,客户端也不会有X-Forwarded-For情况,所以无论是否配置trusted_proxies都不影响)。 Caddy连接SNSIDS,因为客户端直接Caddy,所以Caddy把客户端的IP:121.237.92.*填入X-Forwarded-For,然后把请求发送给SNSIDS。- 因为
SNSIDS配置了trusted_proxies,并信任所有源,所以Caddy传来的X-Forwarded-For内容被保留。 - 最后SNSIDS就可以通过
X-Forwarded-For获取到真实的客户端IP地址。
再看看套了一层EdgeOne的逻辑:
Client ---> EdgeOne ---> Caddy ---> SNSIDS
- 客户端以
IP:121.237.92.*直接连接EdgeOne。 EdgeOne连接Caddy,把客户端IP:121.237.92.*记录到X-Forwarded-For中,Caddy收到EdgeONe发来的请求时有两种情况:- 如果
Caddy没有配置trusted_proxies,那么EdgeOne传来的X-Forwarded-For就会被丢弃 - 如果Caddy配置了
trusted_proxies,那么X-Forwarded-For保持不变。
- 如果
Caddy连接SNSIDS,Caddy把EdgeOne的IP追加到X-Forwarded-For中。- 因为
SNSIDS配置了trusted_proxies,并信任所有源,所以Caddy传来的X-Forwarded-For内容被保留。 - 最后SNSIDS就可以通过
X-Forwarded-For获取到真实的客户端IP地址。