网站建设

分享一个网站防镜像以及解决七牛静态页面跳转的js方案

Jager · 6月19日 · 2016年 · · 9939次已读

导读:作为站长,基本都遇到过网站被人镜像的烦恼吧?最典型的代表就是谷歌搜索,大家都懂的。很多时候反代我们网站的人可能就是拿你的网站练下手,学习下反向代理。当遇到网站被反代,而且排名还比你好的时候,有没有要暴走的冲动…本文分享一种简单有效网站防镜像的方案,适合任何html页面。

分享一个网站防镜像以及解决七牛静态页面跳转的js方案

一、前人分享

挺早之前,看到boke112转载过一篇网站防镜像教程,分享了从.htaccess、php以及js三个方向禁止他人恶意反向代理我们的网站。当时看完觉得三个方法都不完善:

先分析下原理:

.htaccess方案是禁止从代理IP过来的请求

js方案如果发现浏览器url地址不是预期的,那么直接跳转到我们规定的域名。

php方案的原理和js方案类似,通过 $_SERVER[‘SERVER_NAME’] 变量判断域名判断请求是否符合预期,不是就跳转走。

再分析下缺憾:

.htaccess方案,只要请求中含有代理IP(HTTP_X_FORWARDED_FOR不为空)就禁止访问,那如果用CDN的就全部GG了,而且这个值是可以在做反向代理的时候置空的,比如Nginx中可以这样做:

#清空 x-Forward-For
proxy_set_header X-Forward-For '';

php方案中,$_SERVER[‘SERVER_NAME’]的值同样可以在反向代理时伪造,比如:

# 反向代理时自定义 host 值
proxy_set_header Host 'www.google.com.hk';

二、优化版本

已推出最终版,所以,此优化版本可以不用了

js方案,这个也是我今天要分享的方案,之前在boke112我也留言分享了张戈博客的做法,不过好像留言被删除了。文章中的js方案可是可以,但是是写死的跳转。也就是说不管在哪个页面,最终跳转都是首页!显然,这个方案还不够精细化,我们可以做得更细致!

所以,网站防镜像最简单有效的做法就是在<head>部分插入如下js代码即可:

<script type="text/javascript">
/* 如果浏览器域名不是 zhang.ge 将跳转到 zhang.ge 对应的页面*/
if (document.location.host != "zhang.ge") {
    location.href = location.href.replace(document.location.host,'zhang.ge');
} 
</script>

这里对文章js方案做了更细致的改善,也就是跳转之前想将当前url做一次替换,把当前url中的域名换成我们规定的域名,确保跳转后就是用户想要的页面,而不是强硬的跳到首页!

js方案相对于其他方案来说,它的优势在于无法在反代时伪造,浏览器反馈的就是真实的访问情况,直接粗暴。当然,用 Nginx 的第三方内容过滤模块 ngx_http_subs_filter_module 也可以对反代的页面内容进行过滤,当然这是更高级的手法了,这里就不深入介绍了(请注意这段话,本文分享的只是一个方案,并非绝对有效的方法!!)。

三、最终版本

①、WordPress专用版

龙笑天下很好的整理总结了目前几种防镜像的js方案,我看到最后一个借助了img的onerror事件,想法不错,就重新写了一个更简洁,兼容性更好的代码:

add_action('wp_footer','deny_mirrored_websites');
function deny_mirrored_websites(){
    $currentDomain = 'zhangge." + "net'; //此处自行拆分一下自己的域名即可
    echo '<img style="display:none" src=" " onerror=\'this.onerror=null;var str1="'.$currentDomain.'";str2="docu"+"ment.loca"+"tion.host";str3=eval(str2);if( str1!=str3 ){ do_action = "loca" + "tion." + "href = loca" + "tion.href" + ".rep" + "lace(docu" +"ment"+".loca"+"tion.ho"+"st," + "\"' . $currentDomain .'\"" + ")";eval(do_action) }\' />';
}

将此代码添加到主题functions.php文件当中即可。其他类似js可以不用上了,不过也不会冲突。

Ps:本来是丢到wp_head的,经过测试发现图片放到head,浏览器会自动进行错误调整,导致一些本来在head的元素被丢到了body当中,比如style.css,估计网页标准中head里面就不应该放置图片,所以移到了footer当中。

2017年10月21日补充:这段代码会因为onerror死循环造成浏览网页的电脑高负载(CPU飙升),因此在代码onerror触发事件中加入onerror清空机制,即加入this.onerror=null【相关文章】。

②、HTML通用版

既然是js代码,那么肯定可以用于任何符合html规范的页面了。要不是为了可以放到wp的functions.php,都没必要写成php的模式,直接用html代码即可:

<img style="display:none" src=" " onerror='this.onerror=null;var currentDomain="zhangge." + "net"; var str1=currentDomain; str2="docu"+"ment.loca"+"tion.host"; str3=eval(str2) ;if( str1!=str3 ){ do_action = "loca" + "tion." + "href = loca" + "tion.href" + ".rep" + "lace(docu" +"ment"+".loca"+"tion.ho"+"st," + "currentDomain" + ")";eval(do_action) }' />

将以上代码中的

var currentDomain="zhangge." + "net";

自行拆分成自己的域名,避免被镜像代码替换掉,比如:

var currentDomain="www." + "baidu" + ".com";

然后将代码添加到网站的<body>之后即可(不建议放置到<head>里面,具体原因上文已说明),WP一般为header.php文件,其他建站程序请自行搞定,这个版本适合任何网页。

③、通过UA禁止

JS版本效果确实可以,但是有一个小弊端,大部分搜索引擎不能识别js,所以蜘蛛还是能正常抓取镜像网站,有可能会影响SEO。要彻底解决镜像站问题,就得直接禁止镜像网站服务器抓取我们的网页。

有网站已经分享了通过获取镜像网站的服务器IP来禁止抓取,但是镜像网站换一个IP,或者还有其他镜像网站,都无法一劳永逸。所以,我们可以研究镜像服务器抓取时的特征,然后通过禁止特征来解决镜像问题,当然这个方法也不能绝对,因为特征很多时候都是可以伪造的,这里就不多说了。

14年张戈博客就就已经整理分享过网站反爬虫攻略:《服务器反爬虫攻略:Apache/Nginx/PHP禁止某些User Agent抓取网站》,其实这种镜像站和采集基本类似,所以我们需要先分析某一类镜像站的UA特征是什么。

抽空对此次站长朋友纷纷“讨伐”的几个镜像站进行了分析,其实就是在访问镜像网页的时候去查看我们的网站日志,我发现全部请求UA都是PHP/5.4.4:

211.104.158.56 - - [22/Aug/2016:22:03:11 +0800] "GET / HTTP/1.1" 200 64410 "-" "PHP/5.4.45" 211.104.158.56 http

想来也就明白了,这些镜像站点基本都是用的一套程序,甚至环境都是一致的!这让人很容易联想是不是一个人在搞事。。。

好了,废话不多说,既然知道他们的UA了,那么就很好解决了。直接将 PHP这个关键词加入到《服务器反爬虫攻略:Apache/Nginx/PHP禁止某些User Agent抓取网站》 这篇文章的UA清单中即可!

这里,只简单分享一下PHP代码和Nginx代码,其他的请参考前文。

PHP通用版:

//禁止UA为空或含有PHP的请求
$ua = $_SERVER['HTTP_USER_AGENT'];
if(!$ua || preg_match('/PHP/i', $ua)) {
    header("Content-type: text/html; charset=utf-8");
    die('请勿采集本站,因为采集的站长木有小JJ!');
}

将以上代码加入到PHP网站根目录的index.php的<?php 之后即可。

WP适用版:

如果使用上面的php版本,WordPress每次更新就会需要操作index.php,比较麻烦,因此弄个专版:

/**
 * WordPress 禁止UA为空或含有PHP的请求 By 张戈博客
 * 原文地址:https://zhang.ge/5101.html
**/
if(!is_admin()) {
    add_action('init', 'deny_mirrored_request', 0);
}
function deny_mirrored_request()
{
    $ua = $_SERVER['HTTP_USER_AGENT'];
    if(!$ua || preg_match('/PHP/i', $ua)) {
        header("Content-type: text/html; charset=utf-8");
        wp_die('请勿采集本站,因为采集的站长木有小JJ!');
    }
}

将以上代码添加到WordPress主题的functions.php中即可。

Nginx版本:

if ($http_user_agent ~* "PHP") {
     return 403;
}

将以上规则加入到nginx的vhost当中,比如添加到第一个location 之前,然后重载Nginx即可。

我看到有同学使用了htaccess来判断UA,但最后却返回了一个301跳转到首页,虽然也可以,但是有时候镜像程序也是可以抓取301的目标内容的,至少我之前就写过支持301跳转的php代码。

好了,关于镜像网站的问题就整理分享这么多,大家自行选择适合自己的方案即可!

四、拓展延伸

另外,如果是使用https的网站,想将 http 的访问都跳转到 https 又不想弄个301跳转(可能影响SEO),那么上述js代码稍微改改就能完美跳转了:

<script type="text/javascript">
/* 如果当前是http访问,那么跳转到对于的https页面 */
if (document.location.protocol != "https:") { 
    location.href = location.href.replace(/^http:/,"https:");
} 
</script>

看到这,你应该体会到了js的妙用吧?后续应该可以举一反三,多多利用了!

五、七牛镜像

用了七牛的网站,可以试试直接访问我们自定义的七牛静态域名,是不是和我们现在的网站一模一样呢?只是它不会更新而已。很多人肯定下意识的试过张戈博客,发现居然会跳转到对应的博客页面!

比如访问:http://static.zhang.ge/5100.html 会跳转到 https://zhang.ge/5100.html

于是,有不少朋友留言问我,怎么实现301跳转的??

好吧,除非七牛帮忙在CDN节点做设置,将非静态资源请求都跳转到源站,否则张戈也是没办法做301跳转的。因此,你看到的跳转也不是301了,而是js的跳转!

实现原理就是上文介绍的js方案咯!七牛就类似于一个镜像站,而且是静态存储到了七牛节点,因此只能用js方案,在静态页面中实现判断和跳转。

所以,上文分享的js防镜像代码,同样适用于七牛静态页面的自动跳转。只是美中不足的是,大部分搜索引擎并不能识别这个跳转,为了SEO,那你还得继续使用七牛的robots设置了。

当然,如果你添加js代码之前就已经在使用七牛了,那么必须清空七牛中的缓存文件才行,否则是不会跳转的了!因为缓存的代码中没有这段js咯!

最新补充:有人留言说了更好的方案,在Nginx中判断七牛的UA以及抓取的路径就能杜绝七牛缓存不改缓存的页面,要实现也很简单,在Nginx配置中加入如下规则即可:

#匹配请求UA是不是七牛
if ( $http_user_agent ~* 'qiniu-imgstg-spider'){
    set $deny_qn 'y';
}
#匹配请求页面是不是hml或php结尾
if ( $request_uri ~* '\.(html|php)

最后,再啰嗦一句,本文分享的只是小白入门级方案,喜欢喷的朋友建议早点Alt +F4,张戈谢谢你。

 ) {
   set $deny_qn '${deny_qn}es';
}
#匹配首页
if ( $request_uri ~ '^/

最后,再啰嗦一句,本文分享的只是小白入门级方案,喜欢喷的朋友建议早点Alt +F4,张戈谢谢你。

 ) {
   set $deny_qn '${deny_qn}es';
}
#若上述2个条件成立,就拒绝访问
if ( $deny_qn = 'yes' ) {
   return 403;
}

最后,再啰嗦一句,本文分享的只是小白入门级方案,喜欢喷的朋友建议早点Alt +F4,张戈谢谢你。

110 条回应
  1. Nanikl2017-7-19 · 17:34

    你好,使用了最终版本,由于对方镜像站使用的二级目录域名,替换掉域名了可以跳到我们页面但是却无法跳到想要的页面?显示的是我们404页面。需要怎么处理?

    • Jager2017-7-19 · 21:53

      你这个需要定制才行,给你一个思路:过滤对方那个二级目录的名称即可,比如对方二级目录叫 /mirror/

      • Nanikl2017-7-19 · 23:34

        感谢,但是不太懂,比如镜像站是http://www/kciag/assc.asp?
        最终版本需要怎么加代码才可以?

  2. 龙笑天2017-12-8 · 21:32
    if (document.location.protocol != "https:") { 

    这个代码会导致打开http的快照也会转向https吧~

  3. 米辰木2018-1-27 · 11:31

    最近我的一个网站被人镜像了,用了腾讯cdn,把他域名拉黑了,但好像没完全起作用呢?请教下该怎么弄?我用的vps是lnmp一键安装包环境。centos7

  4. al2018-3-16 · 12:57

    大神问个问题,JS最终版本和你之前分享禁止某些User Agent方法里 第三种PHP代码一起用,会有冲突吗。https://zhang.ge/4458.html

    • al2018-3-16 · 13:14

      刚说错了,是最终版里wp专用版和你之前分享禁止某些User Agent方法里 第三种PHP代码一起用,会有冲突吗。 😐