文章目录[隐藏]
今天,本站成功接入腾讯云 CDN,享受高速内容分发网络。
做网站的人都知道,对于 WordPress 而言,保存评论者真实 IP 的重要性。我们经常会遇见恶意进行大量的行为,对于直连的主机,我们可以直接通过 IP 过滤掉这些恶意评论。
而对于套了一层 CDN 或代理的网站,这些方法可能就失效了。因为 WordPress 记录的 IP 是来自 $_SERVER['REMOTE_ADDR']
,而用上 CDN 后,这会变成了 CDN 节点的 IP。
那么真实的 IP 藏在哪里呢?我们该如何通过 Hack WordPress 来使 WordPress 获取到真实的评论者 IP 呢?
真假难辨的访问模式
对于访客而言,我们有这3种常见的访问模式:
- 直接连接网站(用户->服务器)
- 透过 CDN 连接网站(用户->CDN->服务器)
- 透过代理连接网站(用户->代理(->CDN)->服务器)
而会造成麻烦的访问模式,就是第2和第3种。
问题的溯源
前面已简单提过,原因是 WordPress 是通过 $_SERVER['REMOTE_ADDR']
来记录 IP,而当遇到 CDN 时,这个值不再是访客的真实 IP,而变成了访客 CDN 节点的 IP。
而当一个 CDN 或者透明代理服务器把请求转到后面服务器的时候,这个 CDN 服务器会在 HTTP 的头中加入一个记录 $_SERVER['HTTP_X_FORWARDED_FOR']
,它的格式是这样的:访客 IP, 代理服务器 1-IP,代理服务器 2-IP, 代理服务器 3-IP, …
,因此我们可以看到经过好多层代理之后, 访客真实 IP 在第一个位置, 后面会跟一串中间代理服务器的IP地址。
因此,我们从 $_SERVER['HTTP_X_FORWARDED_FOR']
下手就可以取到用户真实的IP地址了。
Hack WordPress
经过查阅资料,WordPress 有一个关键的 Hook 可以供我们使用,那就是 pre_comment_user_ip
,其在开发文档中的表述是:
Filters the comment author’s IP before it is set.
所以,我们只要将以下的代码放在主题的 functions.php
就能解决这个问题(终于进入正题了,好累):
add_filter( 'pre_comment_user_ip', 'nikbobo_get_correct_ip_for_comment' ); function nikbobo_get_correct_ip_for_comment() { if ( empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { $ips = array( $_SERVER['REMOTE_ADDR'] ); } else { $ips = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ); } $ip = array_map( function ( $ip ) { return trim( $ip ); }, $ips ); return $ip[0]; }
但是,如果用了一些高级的访客统计插件的话,可能问题就不止那么简单了,可能要通过修改插件的方式解决。反正我不用这些插件,管他呢~