解决新浪/微博图床图片403错误防盗链问题

缘由

微博图床是网友利用新浪微博上传图片的功能,然后网友将图片的链接进行分享。微博图床的稳定性不用我多介绍,但是由于愈来愈多的网友使用微博做图床,微博官方可能觉得影响服务器或者费用的支出等原因,开始对微博图片添加了防盗链的功能。

新浪微博的图片防盗链:

它的防盗链原理较为简单,只要不是新浪微博的白名单域名请求该图片,服务器会返回一个403的错误码。背后的原理是利用了浏览器的HTTP请求头默认会携带:Referer属性。而这个属性记录了该请求由哪个域名发送的。所以微博图床直接校验该属性的值,只要不是微博允许的域名访问图片链接,将会不予返回图片。下图是我博客请求一张图片的请求头:

Referer请求头

可以看到该请求是由:https://blog.gobyte.cn/post/f9458eff.html发起的,而且这个Referer属性是浏览器默认携带,既然是默认携带,那肯定有关闭的方法。

解决方法1(不推荐)

在HTML的<head>标签里添加mate标签,如下:

1
<meta name="referrer" content="no-referrer" />

不推荐该方法的原因是会导致该页面的所有的HTTP请求都不会携带Referer属性。这会导致部分功能失效,如某些统计信息失效,比如我使用了“不蒜子”的统计功能,会导致失效,所以我推荐方法2.

解决方法2-给图片添加referrerpolicy=“no-referrer”(推荐)

既然不能给所有的HTTP请求添加content="no-referrer",那么我们就仅给图片添加。

在img标签有个属性名叫referrerpolicy,给部分的HTTP请求添加Referer属性。

原生JavaScript语法:

1
2
refStr = imgElt.referrerPolicy;
imgElt.referrerPolicy = refStr;

referrerPolicy可选值:

1
2
3
"no-referrer":表示HTTP头部信息将不会发送 referrer 。
"origin":表示 referrer 只包含策略、主机名、端口等页面源的信息。
"unsafe-url": 这意味着引用者将包括源站和路径(但不包括片段、密码或用户名)。这种情况是不安全的,因为它可能会泄漏路径信息,这些信息已被使用TLS隐藏到第三方。

我对这三个值做了3次测试

no-referrer-测试:

no-referrer


origin-测试:

origin


unsafe-url-测试:

unsafe-url


三者区别如上面三图所示,符合上面的“referrerPolicy可选值”描述。

所以我们只需要给img标签添加:referrerpolicy="no-referrer"即可。

但是仅仅不可能每次都去手动添加,所以要么直接修改模板文件,要么写一段JavaScript,让页面加载HTML完成后,再对img标签进行遍历修改,话不多数,以下是我使用jquery完成的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var link = "" ;
// 遍历所有的img标签
$("img").each( (i,o) => {
var o = $(o);
// 判断图片的链接是否包含sinaimg关键字
if( o.attr("src").indexOf("sinaimg") > 0 ){
// 给这个标签加上referrerPlicy属性
o.attr("referrerpolicy","no-referrer");
// 备份图片的src
link = o.attr("src");
// 重新设置src,让页面重新加载一次图片
o.attr("src",link);
}
});

注意:这段JavaScript代码需要放在HTML的底部,所以当HTML第一次加载完图片的时候,不出意外的话console控制台依然会报403错误,因为首次加载图片的时候JavaScript脚本并没有给img添加该属性,所以理所当然的是403。但是如果把JavaScript代码放在页面的顶部,那么会因为图片的img标签晚于JavaScript的执行,导致JavaScript代码找不到img标签会让功能不生效。

操作方法:

  1. 找到你的主题的JavaScript代码,我是使用pure主题

  2. 我这主题的修改目录:hexo\pure\layout\_common\script.ejs里添加上述代码

  3. 最终修改结果如下:源代码效果
    页面显示效果

  4. 使用其他主题的同学请自行查找对应的文件修改

当然,如果你知道如何修改Hexo的页面模板,直接在模板里给图片标签加上referrerpolicy="referrerpolicy"也可以,但是我不知道如何修改。所以我还提供了方法3。

解决方法3-在生成HTML的时候加上referrerpolicy=”referrerpolicy”

注意,因为我是使用Hexo博客程序,该博客是使用markdown编写文章,最后由HEXO程序进行渲染出HTML文件。所以我直接在markdown里标注要需要添加:referrerpolicy="referrerpolicy"的图片,渲染的时候直接添加该属性。

而Hexo提供了一个自定义函数的功能,操作方法:

  1. 在你的Hexo程序目录的“script”文件夹里(如没有自己新建),创建一个文件“myFunction.js”

  2. 复制以下JavaScript代码到该文件内

    1
    2
    3
    4
    5
    // 给img添加referer policy 标签,解决referer图片防盗链
    hexo.extend.tag.register('s', function(args){
    const image_url = args[0], alt = args[1];
    return `<img src="${image_url}" alt="${alt}" referrerpolicy="no-referrer"></img>`
    })
  3. 在markdown里使用 <% s 图片url alt说明 %>调用。调用代码示例:

    1
    {% s https://ws4.sinaimg.cn/large/96e311f0gy1g3uyql0zj0g20s60lmn71.gif 删除效果 %}
  4. 页面地址为:点我打开效果页面,效果图如下:效果图

    该方法适用于偶尔使用微博图床;因为使用了自定义语法的功能,导致markdown编写的时候不能预览图片。而且每次书写自定义代码尤为的不方便,我个人不太建议使用。

总结:

微博这次加了图片防盗链,虽然是很简单的防盗措施,但是也说明了微博对于图片外链的态度,不喜欢网友使用他们的服务器架设图床,所以以后也可能会有更加厉害的防盗链方法也是可能的。

我个人建议各位同学还是架设一个自己的文件存储系统,至少图片不会有丢失、无法访问的风险,目前各大云服务提供商都有免费的套餐,大家可以了解一下。

本篇文章也是个人思考的总结,最后感谢你的耐心阅读。