首页 > 程序资源 > 【原创】Typecho 在使用 CDN 的情况下获取真实客户端 IP(非覆盖 $_SERVER)

【原创】Typecho 在使用 CDN 的情况下获取真实客户端 IP(非覆盖 $_SERVER)

博客一直在使用 CDN (减速),不是为了给网站加速,因为我站内本身图片等大文件就少,而且(几乎)所有的静态资源都已经放在单独的 CDN 域名上托管了,而页面是动态内容没有缓存,经过 CDN 中转一道铁定是起到了减速作用,但为了安全起见,你懂得...

众所周知,使用 CDN 后, 一般程序默认使用 $_SERVER['REMOTE_ADDR'] or $_SERVER['HTTP_CLIENT_IP'] 获取 IP 的话,都是 CDN 服务器的 IP,而我其实一直不是很关心这个,但是最近看到很多垃圾评论都进来了,还 IP 都一样,就看着很不爽了,于是决定把这个 “脚底的沙子” 掏一掏...

于是,打开 Google,输入 “Typecho CDN IP”,果然你遇到的问题一定都是别人解决过的,准备开抄...

当我看到解决方案,这简单除暴有效通用的方法真是过于真实...

//防止 CDN 造成无法获取客户真实 IP 地址
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $list[0];
}

是的,所有的搜索结果都是这个,文章标题,文章内容,一毛一样,都不知道是谁抄谁的了,有效是真的有效,但是是真的一言难尽,我不服,我要找到正统的解决方案,不行我就去改代码!!!

其实思路很简单,搜索程序内获取客户端 IP 的相关代码,那附近一定藏着什么秘密。

代码全局搜索 “REMOTE_ADDR”,在 /var/Typecho/Request.php:659setIp 方法内,找到到了相关的设置。

这个方法的主要代码是一个 switch,先尝试从 $this->getServer(__TYPECHO_IP_SOURCE__) 中获取 IP,然后才尝试从 $this->getServer('REMOTE_ADDR') 中获取IP,而查看 getServer 相关的代码,发现基本功能就是获取 $_SERVER 内的相关变量。

那么,我们只要在配置文件提前定义好常量 __TYPECHO_IP_SOURCE__ 的值,那么程序就会优先从这个对应 $_SERVER 的成员中获取值。

只要在配置文件(/config.inc.php)加入如下代码即可:

/** 定义 IP 来源 */
define('__TYPECHO_IP_SOURCE__', 'HTTP_X_FORWARDED_FOR');

这也是官方提前预留出的获取 IP 的方案,显然也是官方所希望的✅正确用法。

当然,由于众所周知的原因,HTTP_X_FORWARDED_FOR 是非常不安全的,因为它有被伪造 IP 的风险,想一下,如果某一天你下掉了 CDN ,而又忘记修改这里,那么你的程序就有可能获取到客户端伪造的 IP,而有这样漏洞的程序在网上可是数不胜数,而很多导致漏洞的代码都是新(cai)手(niao)在搜索时,遇到了和上面一样广为传(chao)播(xi)的错误代码所害。

好在大多数 CDN 厂商都会给提供客户端真实IP,除了会把客户端IP加到 HTTP_X_FORWARDED_FOR 外,一般还会有自己定义的 Header 头,比如阿里云的就是 HTTP_ALI_CDN_REAL_IP(这个头是可信的,无法被客户端伪造 / 覆盖 / 修改的)。

所以,我们还可以这样配置(推荐):

在配置文件 (/config.inc.php) 中加入如下配置。

/** 定义 IP 来源 */
define('__TYPECHO_IP_SOURCE__', 'HTTP_ALI_CDN_REAL_IP');

不同的 CDN 厂商会有不同的头,一般官方文档会有给出对应的 Header Name,可以尝试找一下文档,如果找不到也没关系,手动输出你服务器获取到的 $_SERVER 头信息,这里面一定会有一些蛛丝马迹。

比如阿里云,附加了好几个自定义的头信息:

  1. HTTP_ALI_SWIFT_USE_UPSTREAM_TPROXY=on (作用未知)
  2. HTTP_ALI_TPROXY_ORIGIN_PORT=443 (应该是源端口)
  3. HTTP_ALI_TPROXY_ORIGIN_HOST=www.qs5.org (应该是客户端请求的真实域名)
  4. HTTP_ALI_TPROXY_ORIGIN_SCHEME=https (应该是客户端发起的协议)
  5. HTTP_ALI_CDN_REAL_IP=xxx (客户端的真实IP)
  6. HTTP_ALI_SWIFT_STAT_HOST=www.qs5.org (应该是 CDN 配置后台用的域名吧?)
  7. HTTP_ALI_SWIFT_LOG_HOST=www.qs5.org (应该是 后台配置的日志域名?)

至于具体用途,我也没有研究过,不好乱说误导人,只能把我大概能猜到用途的写到括号里面了。

上一篇: 五月&南京,杨絮&夫子庙,中山陵园&392级台阶,你&我,七天南京&四乘飞机。

下一篇: Linux下实现系统启动后每隔3天执行一次脚本。

最近回复

标签