今天在看腾讯云 CDN 统计数据时,发现一个不起眼的 Referer:
按照以往的习惯总是会把一些不熟悉的网站点开看看,结果差点就没发现这个山寨货:一个和本站一模一样的网站,但是里面全是繁体字,评论系统原封不动且正常使用。
我甚至怀疑以前检查的时候我都自动忽略了。因为这次发现的镜像站是因为我发现假冒站的「友链朋友圈」没点开,循环重定向,打算找问题时发现域名不对劲。至于繁体文字我一直以为是 Butterfly 偶发故障,因为点两下简繁切换按钮就好了。
服了,我真的是要吐槽我自己了,为什么每次博客圈发生什么坏事我总是这么迟钝🤮:
- 年初网站外链查的紧时,是蜀黍打电话过来时才把它当回事。(那时候已经看到过 @大大的蜗牛 发表过类似文章,处理措施详见 站内文章这篇文章)
- 前段时间中小博客被盗刷 CDN,我是直到钱包被抠破才意识到事情严重,甚至眼睁睁看着正在被盗刷不知道该干啥。(然而那时候已经看到过 @清羽飞扬 发表过类似文章)
- 现在被镜像了,却不知道已经被镜像 2 个月了,然后才想起来 @杜老师 有发过类似的文章…
既然事情已经发生,那现在我们就着手处理吧。
假冒站点特征
镜像站的地址:gatoelectric.online
。从域名上看不出什么名堂,感觉是个某个做电子的企业。ICP 备案查不到什么信息(废话),Whois 展示如下:
这个来自天津的 zhang💩zhen💩yu 同时也镜像了 这位博主 的网站,可以说是个惯犯了。
Google 搜索「半方池水半方田」到是没搜索到,直接搜域名就搜到了。
通过一些博主的文章了解到,这种镜像站点的行为已经是自动化的了,目的可能是用于养域名,它们的特征有:
- 国内网络无法访问镜像站点,返回 404
- 主页面的语言是繁体
- 伪装成搜索爬虫对网站进行爬取
🛡️防御措施
对网站的各个部分,我们可以采取相应的措施。
为网站添加 JavaScript 脚本
原理是检测当前站点是否为正确站点,否则:
- 弹窗提示框,说明此站点非官方站点。或直接重定向到官方站点。
- 站点加上水印
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| const validDomain = 'uuanqin.top'; const redirectUrl = 'https://blog.uuanqin.top'; const hostname = document.location.hostname; const isLocalHost = (hostname === 'localhost' || hostname === '127.0.0.1');
if (!isLocalHost && !hostname.endsWith(validDomain)) { createWatermark(validDomain) const userResponse = confirm(`警告:本页面非官方页面,可能存在有害信息!建议您立即跳转 ${validDomain} 并向站长举报该镜像站!`); if (userResponse) { window.location.replace(redirectUrl); } }
if (window.top !== window.self) { const userResponse = confirm(`当前访问于嵌套窗口,可能存在侵权行为,请在独立窗口访问 ${validDomain}。`); if (userResponse) { window.open(redirectUrl, '_blank'); } }
function createWatermark(text) { const watermarkDiv = document.createElement('div'); watermarkDiv.style.pointerEvents = 'none'; watermarkDiv.style.position = 'fixed'; watermarkDiv.style.top = '0'; watermarkDiv.style.left = '0'; watermarkDiv.style.width = '100%'; watermarkDiv.style.height = '100%'; watermarkDiv.style.zIndex = '9999'; watermarkDiv.style.opacity = '0.35'; watermarkDiv.style.background = 'transparent'; watermarkDiv.style.overflow = 'hidden'; watermarkDiv.style.display = 'flex'; watermarkDiv.style.justifyContent = 'center'; watermarkDiv.style.alignItems = 'center'; watermarkDiv.style.flexWrap = 'wrap';
const watermarkText = document.createElement('div'); watermarkText.innerText = text; watermarkText.style.color = '#8d8d8d'; watermarkText.style.fontSize = '30px'; watermarkText.style.transform = 'rotate(-30deg)'; watermarkText.style.whiteSpace = 'nowrap'; watermarkText.style.margin = '20px'; watermarkText.style.textShadow = '2px 2px 5px rgba(0, 0, 0, 0.5)';
for (let i = 0; i < 60; i++) { watermarkDiv.appendChild(watermarkText.cloneNode(true)); }
document.body.appendChild(watermarkDiv); }
|
js 引入前记得做混淆处理:JavaScript Obfuscator Tool,勾选 unicode escape sequence 选项把中文进行转义处理。
效果立竿见影,几乎一发布就被假冒镜像站捕获到:
注意,后续更改 Js 时注意把文件名也改一改,因为镜像站的服务器有缓存。
Waline 评论系统设置安全域名
Waline 评论内容能被镜像站显示是我完全没想到的。我们可以在环境变量配置安全域名。详看:服务端环境变量 | Waline
效果为评论内容不加载,且禁止评论:
CDN 防盗链黑名单
腾讯云 CDN 访问控制开启防盗链黑名单:
注意:
- 不用选「拒绝空 referer 访问」,这影响范围比较大,容易误伤一些正常访问,不好处理。
- 对图床防盗链即可,意思意思。对网站不用防盗链。因为这会导致用户点击你的跳转弹窗时被官方站点拒绝。
效果:
🗡️反制措施
获得伪站的「谷歌站长」所有权
用自己的 Google 小号,在谷歌站长新加一个网站,网址就是镜像站的网址。利用镜像站原封不动爬取资源的特点,通过 HTML 验证获得镜像站的「谷歌站长」所有权。
Hexo 博客放置步骤可以是:
- 放到 source 文件夹下
- 在配置
_config.yml
中指定文件不被渲染
1 2
| skip_render: - googlefcd336221d7decf8.html
|
- 正常发布即可
然后,桀桀桀…(此部分需等待谷歌完成数据整理,后续博主会更新)
在 Nginx 中将假爬虫的请求转发到其他站点
首先获得谷歌爬虫的 IP 段:googlebot.json
将 IP 段转换成这种形式:
1 2 3
| 66.249.76.96/27 1; 66.249.77.0/27 1; 66.249.77.128/27 1;
|
可以找 AI 帮忙生成代码而不是直接要结果,毕竟 IP 太多了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import json
input_file = 'googlebot.json' output_file = 'converted_ipranges.txt'
with open(input_file, 'r', encoding='utf-8') as f: data = json.load(f)
ip_ranges = data.get("prefixes", [])
with open(output_file, 'w', encoding='utf-8') as f: for range in ip_ranges: if 'ipv4Prefix' in range: f.write(f'{range["ipv4Prefix"]} 1;\n') elif 'ipv6Prefix' in range: f.write(f'{range["ipv6Prefix"]} 1;\n')
print(f"转换结果已保存到 {output_file}")
|
打开 Nginx 日志(/var/log/nginx
目录下),搜索可疑爬虫的 User Agent,如果爬虫的 IP 不在官方的列表中,就说明这个爬虫是假的。
在 Nginx 配置文件(http
块)中加入以下字段:
1 2 3 4 5
| # 加载 IP 白名单文件 geo $crawler_ip { default 0; include /etc/nginx/conf.d/googlebot_ipranges/converted_ipranges.txt; }
|
主站 location
块中加入判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| server {
listen 443 ssl; server_name blog.uuanqin.top; access_log /var/log/nginx/host.access.log main;
location / { root /var/www/blog.uuanqin.top; index index.html index.htm;
set $temp ""; # 符合UA if ($http_user_agent ~* 'compatible; Googlebot/2.1;') { set $temp "${temp}1"; } # 但不符合IP段时自动反代指定网页 if ($crawler_ip != 1) { set $temp "${temp}1"; }
if ($temp ~* "11") { proxy_pass https://www.cac.gov.cn; # 网信办 break; # 添加 break 语句,确保后续的处理被中断 } }
# 此处省略其他配置 }
|
配置更改后记得重启 Nginx:
特么的,这些东西花了我几个小时排查,GPT-4o 也不靠谱。可能是我的 Nginx 版本原因把,写个简单的「与」条件判断够复杂的。
geo
、map
必须在 server
块外面
if
条件语句写在 location
里面
if
条件语句不能嵌套
if
条件语句不能使用「与」「或」判断
if
和括号 (
中间必须有空格
proxy_pass
接的网址最后不能是 /
- 奇怪的正则表达式
我们可以通过修改输出日志的格式完成 Nginx 的调试:
1 2 3 4 5 6 7
| log_format alogformat '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for -- is_crawler_ip: $crawler_ip | fakeBotWillBe11: $temp "';
server{ access_log /var/log/nginx/host.access.log alogformat; }
|
通过日志查看指定的 IP 是否被拦截。
然而并没有什么用,因为伪站不只使用假爬虫伪装,它可能还使用 Cloudflare 的代理结点进行爬取。
向各种服务商举报滥用
我们可以向 Google、Bing、Cloudflare、Aliyun、域名商以 DMCA 为理由举报滥用行为。
不懂有没有用哈。
本文参考
镜像站相关:
Nginx 相关: