新浪图床防盗链始末
新浪图床加防盗链检测已经是很久以前的事了,那时我还在用静态博客,虽然也中了招,但只有几篇帖子,影响不大。但今天有博友留言仍未解决,希望有办法暂时恢复图片显示,慢慢迁移,所有我就借花仙佛,总结一下已有的快速恢复和迁移方法。
[collapse title="可忽略内容"]
问题发生后,万能网友很快发现,空 referrer
头仍能获取图片,这说明新浪未做强防盗链检测。已有机制是校验 HTTP 协议头的 referrer
字段,即来源验证。具体来说,假如你的帖子 http://blog.xx.com/123.html
引用了一张新浪图片,浏览器向服务器请求该图片时,会把 referrer=http://blog.xx.com/123.html
一并发送过去,新浪检查到非官方来源便返回了 403
禁止访问。如果强制发送 referrer=
或不发送该字段,服务器仍正常返回,所以就有了以下各种 no-referrer
配置。
前端
META
方式一,在每个页面的 head
部分添加 meta
标签,会导致站点评论、统计等功能失效,因为它们同样依赖来源。
<meta name="referrer" content="no-referrer">
IMG
方式二,给每张图片单独配置 referrer
策略,不兼容 IE、Edge 和 Safari on iOS。
<img src="demo.jpg" referrerpolicy="no-referrer">
IFRAME
方式三,将图片放到 iframe
,每张图片都写这么多代码,没人有耐心,且有相同的兼容性问题。
<script>
function iframeLoaded(target) {
var img = target.contentDocument.images[0];
target.width = img.width;
target.height = img.height;
}
window.sina = '<img src="//wx4.sinaimg.cn/large/007iuyE8gy1g2g8p3ovr3j30t314lhdt.jpg">';
</script>
<iframe
referrerpolicy="no-referrer"
src="javascript:parent.sina"
scrolling="no"
frameborder="0"
onload="iframeLoaded(this)">
</iframe>
后端
Referrer-Policy
方式四,通过 Ngnix
、Apache
等 Web 服务器,直接告诉浏览器 Referrer-Policy: no-referrer
,效果同方式一,意味着有相同的副作用。
Nginx
add_header Referrer-Policy no-referrer;
Apache
Header always set Referrer-Policy "no-referrer"
反向代理
方式五,反代,让后端构造任意 referrer
,如 referrer=https://m.weibo.cn
获取图片,转发给前端,这样前端就无需任何配置,也就不会产生副作用。
可以用自己的 服务器、CDN 和 Cloudflare 等搭建反代,也可使用如下第三方代理。
<!-- 新浪官方未加验证域名 -->
<img src="//tva1.sinaimg.cn/large/007iuyE8gy1g2g8p3ovr3j30t314lhdt.jpg">
<!-- Wordpress 官方反代 -->
<img src="//i0.wp.com/wx4.sinaimg.cn/large/007iuyE8gy1g2g8p3ovr3j30t314lhdt.jpg">
<!-- 百度图片搜索反代 -->
<img src="//image.baidu.com/search/down?tn=download&url=https://wx4.sinaimg.cn/large/007iuyE8gy1g2g8p3ovr3j30t314lhdt.jpg">
替换链接
有了反代服务器后就要把站点所有新浪图片都替换成反代链接。
服务器替换
可通过 Nginx
或 Apache
插件实时检查。我没有动力详细介绍,读者可参考 Nginx 内容替换模块 http_substitutions_filter_module 实用案例分享 或 使用 mod_ext_filter 组件在 Apache 中实现输出内容的替换,为所有页面增加统计功能。
下面是 ngx_http_substitutions_filter_module
的配置示例,这个模块要自行编译安装。
sub_filter '[0-9a-z]{3}.sinaimg.cn/large/' 'i0.wp.com/wx4.sinaimg.cn/large/' ir;
数据库替换
如果不熟悉 Nginx
编译安装,可以使用数据库替换的方法,Typecho 参考 Typecho 网站域名更换方法,Wordpress 参考 WordPress 迁移站点更换域名为新域名的 N 种方法。注意备份数据库,执行命令时仔细甄别表名,字段名,不可无脑操作。
[/collapse]
浏览器替换
如果以上内容都不熟悉,可直接使用 JS 代码在浏览器替换。对于 本主题
,依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展
,将代码加入到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)
。其他主题,加入到主题对应的 header.php
中的 </head>
标签前。
<script>
// 临时替换新浪图床为反代链接
document.addEventListener('DOMContentLoaded', initSinaProxy);
function initSinaProxy() {
var sinaImgs = document.querySelectorAll('img[src*="sinaimg.cn"]');
for (var i = 0; i < sinaImgs.length; i++) {
var img = sinaImgs[i];
img.src = '//tva1.sinaimg.cn/large/' + img.src.split('/').pop();
}
}
</script>
如果你开启了 PJAX
,可能需要单独加入回调函数。对于本主题,依次进入 控制台 - 外观 - 设置外观 - PJAX(BETA) - PJAX RELOAD
,将 initSinaProxy();
添加进入即可。
迁移
前面说了这么多 Linux 操作,还是挺麻烦的,关键是我没有动力详细写,如有困难可留言,我宁愿直接操作服务器。Typecho 或 Wordpress 用户可使用链接中的迁移工具简化操作。
最后,今后一定要将所有图片放到自己的 CDN,同时在其他地方按文章名称建立备份文件夹,以防数据丢失。