网站防镜像这件事,配Nginx拦截规则加JS域名检测就能解决80%的克隆问题,难的是十个站、五十个站怎么批量配、怎么统一管、怎么让每个站的规则不出错
有人用你的域名、你的页面结构、你一个字一个字写出来的内容,换了个域名原封不动挂上去,百度蜘蛛来爬的时候把镜像站当成了原创。你这边流量被分流,排名往下掉,镜像站反倒越爬越高。这比采集还恶心——采集好歹只偷内容,镜像直接把你整个站点克隆过去,连logo、导航、CSS文件名都不带改的。
解决单站被镜像的技术手段其实很成熟:Nginx配一个host白名单、加一段JS域名检测跳转、referer防盗链、Cloudflare开个hotlink保护。一个站配完可能十分钟就搞定。但如果你有十个站、二十个站、五十个站呢?每个站手动去配一遍Nginx配置、每个站单独改JS里的域名变量、每个站单独设CDN规则——光是核对域名有没有写错就能把人搞崩溃。
防镜像批量管理,四条防线从源头到兜底
| 1 | Nginx层:统一include模板,按host白名单拦截,不认识的域名直接return 444 |
| 2 | JS前端层:页面内嵌域名自检脚本,检测到非授权域名自动跳回源站 |
| 3 | CDN层:Cloudflare WAF自定义规则,批量设置referer白名单和hotlink保护 |
| 4 | 监控层:定时搜索站点标题关键词,发现新镜像域名自动报警 |
一、镜像克隆到底是怎么实现的,哪些手段能真正拦住它
镜像站克隆源站的手法主要有四种。第一种是DNS直接解析——攻击者把自己的域名A记录指向你服务器的IP,如果你的Nginx没有做host过滤,直接接受所有域名请求,那就等于敞开门让人随便进。第二种是反向代理转发——攻击者在自己的服务器上配Nginx反向代理,把用户请求转发到你的源站,拿到响应后再原样返回,用户的浏览器里显示的是攻击者的域名,内容却是你的。第三种是静态整站复制——用HTTrack或wget之类的工具把你的整个网站抓下来,HTML、图片、CSS、JS全打包,换个服务器部署。第四种是iframe全屏嵌入——攻击者在自己网站上用一个100%宽高的iframe把你的站点套进去,用户看到的是你的内容,地址栏却是攻击者的域名。
针对这四种手法,防线也要分四层来布。DNS解析型镜像靠Nginx host白名单拦截,反向代理型镜像靠检测X-Forwarded-For等代理头拦截,静态复制型镜像靠JS域名自检脚本兜底,iframe嵌入型镜像靠X-Frame-Options响应头禁止。四层防线中,Nginx host白名单是门槛最低、性价比最高的一层,拦住了DNS解析型镜像这一大头,剩下的再用JS和响应头兜底。
DNS解析型镜像
攻击者域名A记录指向你的IP
防御:Nginx host白名单
反向代理型镜像
攻击者服务器转发请求到源站
防御:检测代理头+IP限制
静态复制型镜像
整站HTML/CSS/JS打包部署
防御:JS域名自检跳转

iframe嵌入型镜像
全屏iframe套壳你的站点
防御:X-Frame-Options响应头
二、Nginx host白名单,一个站十分钟,十个站怎么不写成灾难现场
单站配Nginx host拦截很简单,在server块里加一段判断:
server {listen 80;server_name your-domain.com www.your-domain.com;# 拒绝非授权域名if ($host !~* ^(your-domain.com|www.your-domain.com)$) {return 444;}}return 444是Nginx特有的非标准状态码,连接直接被关闭,不给攻击者任何反馈信息,比403更干净。单站这么配没问题,但站群场景下,十个站就是十个server块,每个块的server_name和if判断里都要写域名。如果手工一个一个填,域名拼错一个字母、漏掉www前缀、正则里少写一个竖线,排查起来比写配置还花时间。
批量管理的核心思路是把host白名单逻辑抽象成一个独立的conf文件,每个站点的配置里用include引入。先在/etc/nginx/conf.d/下建一个anti-mirror.conf模板:
# /etc/nginx/conf.d/anti-mirror-common.conf# 所有站点统一引入此文件# 拒绝直接IP访问(隐藏源站)if ($host ~* ^\d+\.\d+\.\d+\.\d+$) {return 444;}# 拒绝常见代理头标记set $block_proxy 0;if ($http_x_forwarded_for) {set $block_proxy 1;}if ($http_x_forwarded_host) {set $block_proxy 1;}if ($block_proxy = 1) {return 444;}# 禁止被iframe嵌入add_header X-Frame-Options "SAMEORIGIN" always;# 防盗链(保护静态资源)location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|zip|rar|doc|docx)$ {valid_referers none blocked server_names;if ($invalid_referer) {return 403;}}然后在每个站点的server块里,host白名单用map或if来配,其余逻辑统一include:
server {listen 80;server_name site-a.com www.site-a.com;# 各站点独有:host白名单if ($host !~* ^(site-a.com|www.site-a.com)$) {return 444;}# 统一引入公共防镜像规则include /etc/nginx/conf.d/anti-mirror-common.conf;# 站点具体配置...root /www/site-a;index index.html;}这样做了之后,每个站点的配置文件只需要维护两行差异:server_name和host白名单的正则。公共规则改了任何一处(比如新增一个代理头检测、调整防盗链的文件类型),所有站点自动生效。十个站、五十个站,改一处就够了。
批量部署脚本思路:准备一个站点域名列表(site-a.com, site-b.com, site-c.com...),写一个shell脚本遍历这个列表,自动生成每个站点的server块,把server_name和host白名单自动填入。新增站点时只需在列表里加一行域名,重新执行脚本生成配置,nginx -t 检查语法,nginx -s reload 生效。三分钟完成五十个站的防镜像规则部署。
三、JS域名自检脚本,Nginx被绕过后最后一道防线
Nginx host白名单只拦得住DNS解析型镜像和反向代理型镜像。如果攻击者把你的站点整站静态复制下来,换台服务器直接部署,Nginx管不着那台服务器。这时候就靠JS域名自检脚本兜底——页面在浏览器加载后,第一时间检查当前域名是不是你自己的,不是就跳转。

单站的JS自检很简单,一句话:
<script>(function() {var allowedHosts = ['site-a.com', 'www.site-a.com'];var currentHost = window.location.hostname;var isAllowed = allowedHosts.indexOf(currentHost) !== -1;if (!isAllowed) {// 检测到镜像站,跳回源站var targetUrl = 'https://site-a.com' + window.location.pathname + window.location.search;window.location.replace(targetUrl);}})();</script>站群场景下,这个脚本需要每个站点一个不同的allowedHosts数组。手工改五十个站的JS太蠢了,方案是用一个全局JS文件,通过页面上的data属性来注入当前站点的授权域名列表:
<!-- 在每个站点的页面中,HTML标签上带一个data属性 --><html data-allowed-hosts="site-a.com,www.site-a.com"><!-- 引入统一的防镜像检测脚本 --><script src="/assets/anti-mirror.js"></script>anti-mirror.js这个文件所有站点共用,逻辑从data属性读取当前站点的域名白名单:
// /assets/anti-mirror.js —— 所有站点共用(function() {var htmlEl = document.documentElement;var hostsAttr = htmlEl.getAttribute('data-allowed-hosts');if (!hostsAttr) return;var allowedHosts = hostsAttr.split(',').map(function(h) {return h.trim();});var currentHost = window.location.hostname;if (allowedHosts.indexOf(currentHost) === -1) {// 拼接跳转URLvar targetHost = allowedHosts[0];var targetUrl = 'https://' + targetHost + window.location.pathname + window.location.search;window.location.replace(targetUrl);}})();新增一个站只需在HTML标签上改一行data属性,JS文件不用动。如果某个站点加了www子域名、或者换了域名,改一行属性就搞定,不用翻到JS文件里找allowedHosts数组。
注意:JS域名自检只能对付静态复制型镜像,对付不了反向代理型镜像——反向代理型镜像站的域名就是攻击者的域名,但页面内容是实时从你源站拉取的,JS脚本也在你源站上,检测到的currentHost其实是攻击者的域名,脚本会正常触发跳转。但攻击者如果足够聪明,可以在反向代理时把JS脚本过滤掉。所以JS自检只能做兜底,核心防线还是在Nginx层面。
四、CDN层的批量防护,Cloudflare WAF自定义规则和hotlink保护
如果你的站点接了Cloudflare(或者其他CDN),CDN层可以再补一道防线。CDN的优势在于,它挡在用户和源站之间,恶意请求在到达你服务器之前就能被拦截,不消耗你的服务器资源。
Cloudflare免费版提供5条WAF自定义规则,可以覆盖以下防护场景:
| 防护场景 | WAF规则表达式 | 动作 |
|---|---|---|
| 阻止恶意爬虫UA | (http.user_agent contains "HTTrack") or (http.user_agent contains "wget") or (http.user_agent contains "curl") | Block |
| 防盗链(图片等静态资源) | (http.request.uri.path contains ".jpg") and (not http.referer contains "your-domain.com") | Block |
| 阻止非浏览器UA | not http.user_agent contains "Mozilla" | Managed Challenge |
| 速率限制 | (http.request.uri.path contains "/wp-admin") | Rate Limit |
Cloudflare的免费版5条规则对于站群来说确实不够用——你有十个站,规则只能设5条,没法给每个站配专属规则。解决方案有两个:一是升级Pro版(20条规则)或Business版(更多规则);二是利用Cloudflare的"Scrape Shield"功能,它提供hotlink保护(防盗链)和邮件地址混淆,这些是全局开关,不占WAF规则配额。
Scrape Shield(免费)
Hotlink保护、邮件混淆、服务器端排除,全局开关,不限站点数

WAF自定义规则(免费5条)
UA拦截、referer校验、速率限制,通用规则可覆盖所有站点
IP访问规则(免费不限)
阻止特定IP/ASN/国家,发现镜像源IP后直接封禁
速率限制(免费1条)
每个IP每分钟N次请求,防高频采集,对所有站点生效
五、怎么知道自己被镜像了,以及发现后怎么处理
防是防在前面的,但总有漏网之鱼。定期主动巡检才能知道哪些域名在镜像你的内容。最直接的方法是在百度里搜自己站点的首页标题全文(用双引号精确匹配),如果搜出来有其他域名,点进去看看是不是镜像站。搜索引擎收录的镜像站是最需要优先处理的,因为它直接影响你的排名。
站群场景下手工搜五十个站的标题不现实。可以写一个简单的Python脚本,读取站点列表,调用搜索引擎API(或直接用requests模拟搜索),检测搜索结果中是否有非授权域名:
# mirror_detect.py —— 批量检测站点是否被镜像import requestsfrom bs4 import BeautifulSoupSITES = [{"domain": "site-a.com", "title": "站点A的首页标题全文"},{"domain": "site-b.com", "title": "站点B的首页标题全文"},# ... 更多站点]for site in SITES:# 模拟百度搜索(仅供演示,生产环境用官方API)query = f'"{site["title"]}"'url = f"https://www.baidu.com/s?wd={query}"# ... 解析搜索结果,检查是否有非授权域名出现# 发现异常则输出告警:域名、镜像域名、搜索结果URL发现镜像站后,处理路径分三步。第一步技术封堵:从Nginx日志里找到镜像站的来源IP(访问一个只有你知道路径的特殊文件,观察哪个IP来请求了),在服务器防火墙或Nginx里封掉这个IP。第二步平台投诉:向镜像域名的注册商、托管商、CDN服务商提交DMCA投诉。第三步搜索引擎举报:在百度站长平台提交"侵权举报",说明镜像站抄袭你的原创内容。
| 处理步骤 | 操作 | 生效时间 | 效果 |
|---|---|---|---|
| 1. 技术封堵 | Nginx封IP、CDN加黑名单 | 即时 | 镜像站立即无法访问源站 |
| 2. 平台投诉 | 向注册商/托管商提交DMCA | 1-7天 | 镜像域名被暂停解析或下架 |
| 3. 搜索举报 | 百度站长平台侵权举报 | 3-15天 | 镜像站从搜索结果移除 |
六、五十个站的防镜像配置,一次配完不用再改的批量方案
把前面讲的几个层面串起来,一个站群的完整防镜像体系应该是这样的:
- Nginx层:每个站点server块里include统一的anti-mirror-common.conf,host白名单用域名列表自动生成。搞定DNS解析型+反向代理型镜像。
- JS层:统一anti-mirror.js文件,每个站点的HTML标签上设置data-allowed-hosts属性。搞定静态复制型镜像。
- CDN层:Cloudflare Scrape Shield全局开启hotlink保护,WAF自定义规则配通用UA拦截+referer校验。搞定流量盗刷和爬虫采集。
- 响应头:Nginx统一配置里加X-Frame-Options: SAMEORIGIN和canonical标签。搞定iframe嵌入+搜索引擎认源。
- 监控层:Python脚本每周跑一次,自动搜索站点标题检测新出现的镜像域名,发现异常发通知。
如果是用UC建站系统管理的站群,防镜像这件事可以做到更省心。系统自带独立IP+独立部署架构,每个站点Nginx配置独立,公共防护规则模板化统一下发,新增站点时自动生成host白名单和JS域名检测属性。配合站群监控看板,哪个站被镜像了、哪个站有异常流量波动,一眼就能看到。
防镜像不是一锤子买卖。今天配好了规则,明天攻击者换了IP换了UA换了手段,你得能跟上。但话说回来,把基础的四层防线先搭好——Nginx host白名单+JS域名自检+CDN hotlink保护+定时监控——这四样做扎实了,90%的镜像克隆手法到你这里就撞墙了。剩下的10%是高级攻击者,他们有绕CDN找源站IP的手段,有动态切换UA和IP的能力,但那已经是另一个级别的对抗了。对大多数站长来说,先把这四层做好,就已经比裸奔强太多了。
最后说一句:防镜像工具选什么不重要,重要的是你有没有"批量"这个概念。一个站手工配一次很简单,五十个站手工配五十次不出错,几乎不可能。把公共逻辑抽成模板,把站点差异压缩到一行配置,把新增站点做成自动化脚本——这三个习惯,比任何一款具体工具都管用。
