防盗链基础

1. 盗链是什么?

盗链是指将其他网站上的图片、视频或其他媒体文件,显示到自己的网页上。

这种行为通常会给被链接的网站带来额外的带宽消耗和资源浪费,而且可能侵犯了原始网站的版权。

2. 为什么会有盗链?

假设有这样一个场景:前端同学 A 想开发一个技术博客,用来记录自己的技术成长历程。他购买了一台云服务器,并使用开源的博客框架进行了部署。

但文章中有很多图片,而服务器的带宽配置较低,图片加载很慢,你有什么好办法吗?

从技术的角度来看,可以通过购买内容存储服务(如对象存储服务 - OSS),来实现对图片资源的集中存储。同时,开启 CDN(内容分发网络)服务,可以实现对静态资源的快速访问加速。

那有没有更简单而且免费的方案呢?

大部分人可能会在查找资料后,会选择“免费版图床”!

图床(Image Hosting Service)是一种在线服务,它允许用户将图片上传到互联网上的服务器,并生成图片的外部链接(URL)。这个外部链接可以在网页、社交媒体、论坛等地方使用,以展示或分享图片。图床通常用于在网页上显示图片,以减轻网站服务器的负担,同时提高页面加载速度。

图床的主要优势是避免在网站服务器上存储大量图片文件,从而节省存储空间和带宽。此外,图床还可以提供一些额外的功能,如图片压缩、管理、分享、编辑等。

以我之前使用过的 Chrome 的插件“即刻图床”(现已被下架)为例,上传图片后,即可获取对应的 CDN 访问链接。

图片

图床的用户界面

图片

图床的配置页面

我们可以发现,这个插件可以提供“58 同城”、“京东”等网站的图床及 CDN 服务,本质上,这种图床属于“盗链”。

那么为什么会出现盗链?

  • 一方面是因为很多人不想承担资源存储和带宽的成本

  • 另一方面也是因为对应的厂商存在技术漏洞或者防护措施太过薄弱。

3. 盗链与防盗链的博弈

我们所说的“防盗链”,其实就是与盗链者的博弈。

本文主要围绕图片的“盗链”与“防盗链”展开。

3.1 Round 1 - 搭建一个免费图床与设置可访问的 referer

3.1.1 盗链者

所谓的“免费图床”,大部分都是盗用其他公司的 OSS 及 CDN 资源。

大部分的网站或者 App 基本都有图片上传的功能,比如最常见的用户头像上传。开发者完全可以模拟正常用户,将个人网站上的图片上传请求转发到其他的网站,拿到返回的 CDN 地址后,用于自己的网站。

以京东的“评价晒单”为例(仅供技术学习):

图片

图片

通过上传一张图片,我们可以看到对应的上传请求,通过直接复制 Node.js 的请求链接,我们就拿到了一个可以直接在 Node.js 中使用的请求方法。

图片

将请求体中的数据换成自己的图片,然后对外提供一个上传的转发接口,就能依托京东,实现了一个简易版本的图床。当然,这种方案会有一些缺点,比如登录态需要定期更新。

fetch("https://club.jd.com/myJdcomments/ajaxUploadImage.action", {
  "headers": {
    "accept": "*/*",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
    "cache-control": "no-cache",
    "content-type": "multipart/form-data; boundary=----WebKitFormBoundaryRE3eavlaBJiyXn9Q",
    "pragma": "no-cache",
    "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"macOS\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "cookie": "xxxx",
    "Referer": "https://club.jd.com/myJdcomments/orderVoucher.action?ruleid=xxxx",
    "Referrer-Policy": "strict-origin-when-cross-origin"
  },
  "body": "------WebKitFormBoundaryRE3eavlaBJiyXn9Q\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\npolicy-1.png\r\n------WebKitFormBoundaryRE3eavlaBJiyXn9Q\r\nContent-Disposition: form-data; name=\"PHPSESSID\"\r\n\r\nmvpjl6muuk705ipboi3ia0b461\r\n------WebKitFormBoundaryRE3eavlaBJiyXn9Q\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"policy-1.png\"\r\nContent-Type: image/png\r\n\r\n\r\n------WebKitFormBoundaryRE3eavlaBJiyXn9Q--\r\n",
  "method": "POST"
});

最后将接口返回的 CDN 链接用于个人网站,就实现了最简单的盗链。

3.1.2 防盗链

下面我们来看下怎么防盗链,首先需要知道图片的请求是从哪里发出的。

可以实现这一功能的有请求头中的 origin 和 referer

origin 表示当前请求资源所在页面的协议和域名,用来说明请求从哪里发起的,但是一般在 CORS 跨域请求中才会带上,普通请求中没有。

图片

带 origin 的请求头

而referer 记录当前请求资源所在页面的完整路径,我们一般可以使用 Referer 进行最简单的过滤,也就是仅支持指定的 referer 访问我们的资源。

图片

阿里云 OSS 的防盗链配置页面

正确英语拼写应该是 referrer,由于早期 HTTP 规范的拼写错误,为了保持向后兼容就一直延续下来

对于非法访问,一般会返回默认图或者 403

如果是自己的服务器,可以直接通过代理服务器进行配置,以 Nginx 的配置为例:

location ~.*\.(gif|jpg|png|flv|swf|rar|zip)$
{
    valid_referers none blocked test.com *.test.com;   //加none的目的是确保浏览器可以直接访问资源
    if($invalid_referer)
    {
        #return 403;  // 直接返回403
        rewrite ^/ http://www.test.com/403.jpg;//返回指定提示图片
    }
}

3.2 Round 2 - 空 referer 与更精细的过滤策略

3.2.1 盗链者

上面的阿里云防盗链页面中,有个额外选项叫“是否允许空 Referer”,正常情况下,这选项一般选“允许”,因为一旦禁止空白 referer 请求,用户将不能在浏览器中直接打开图片,下载图片也有可能出现问题,所以大多数的图床都是允许空白 referer 请求的,而这便是弱点所在。

图片

直接访问掘金图片的请求头

假如我给页面的 referrer 设置成 never,或者将图片的 referrer 单独设置 no-referrer,图片请求时就不会在请求头中带上 referer

<meta name="referrer" content=“never”>
// or 
<img referrer="no-referrer" src="xxxx"/>

referrer 的取值及含义,大家可以参考 MDN。

PS: 在 Chrome 中,即使页面上设置 <meta name="referrer" content=“never”>,background-image 中的图片请求还是会带上 referer,但火狐中不会带上。

3.2.2 防盗链

从防盗链的角度,怎么针对空白 referer 进行优化呢?

空白 referer 不一定就意味着盗链,我们得理一理哪些是敌军哪些是友军,再决定是拉意大利炮还是拉意大利面。

  • 敌军:使用各种手段隐藏 referer,在非我军的网页上使用我军的图片;

  • 友军:直接用浏览器访问图片或只用其他工具下载图片。

可见,其核心区别就是图片是不是放在 <img> 标签里的,而这正是在无 referer 的情况下,甄别请求是否来自盗链的关键。

Accept 是一个较少被关注的请求头部,用来告知服务端哪些内容类型是客户端可以处理的,且有权重的概念,表示“客户端更期待服务端返回哪种类型”,很显然, 标签引起的请求“更期待返回图片”,而直接访问地址的请求则“更期待返回 HTML”(浏览器无法提前知道目标是一张图片),而使用一些工具下载图片则倾向于没有任何期待,给啥都行。

以下是做的几个实验,可以说明这个问题。

Chrome 浏览器因  标签而发起的请求:

Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: https://xxx.xxx.com/
User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36

Chrome 浏览器直接访问图片地址而发起的请求:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36

使用 curl 下载图片而发起的请求:

Accept: */*
User-agent: curl/7.60.0

可见,相比于其他情况,因  标签而发起的请求明显地更倾向于“接收一张图片”,根据这一情况,修改后的防盗链策略为:

  • 如果有 referer:

    • referer 在白名单内,判定为正常请求;

    • referer 不在白名单内,判定为盗链;

  • 如果没有 referer:

    • accept 内容最靠前的是“image”,则判定为盗链;

    • 其他默认判定为正常请求。

这个策略相比于禁止空白 referer 访问,已经柔和了很多,只是在默认允许空白 referer 访问的基础上,针对特殊情况增加了防护策略,误杀的可能性较低。

但如果用户使用的浏览器并没有按权重提供 Accept,服务端就可能将盗链误判为正常请求。但只要只要针对绝大多数浏览器能够正常判定为盗链,对盗链者来说已经是致命的打击了。

其他不带 referer ,可能会引发误判的场景:

  • 在部分开启了隐私模式的浏览器上,referer 就是空

  • 在 https 的页面上请求 http 的图片,也不会携带 referer

3.3 Round 3 - 资源转发与 Token 签名

3.3.1 盗链者

如果按上面的方法配置,盗链者还有办法吗?

还真是有,那就是做一层资源的转发,在转发服务中,直接设置请求头中的 referer

以 Node.js 服务为例:

const express = require('express');
const request = require('request');

const app = express();
const port = 3000;

app.use((req, res, next) => {
  // 设置允许跨域访问
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

app.get('/proxy', (req, res) => {
  const { url } = req.query;

  if (!url) {
    return res.status(400).send('Missing "url" parameter');
  }

  const headers = {
    // 设置 Referer 头部,可以使用你的网站 URL 或其他合适的值
    'Referer': 'https://yourwebsite.com',
  };

  // 发起对第三方资源的请求
  request({ url, headers }, (error, response, body) => {
    if (error) {
      return res.status(500).send('Error fetching the resource');
    }

    // 将第三方资源的响应直接转发给客户端
    res.send(body);
  });
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

在使用时,只需要在原来 url 前增加自己的转发服务链接,比如 https://xxx.xx.com/proxy?url=xxxxx

不过这种方式需要利用个人服务器进行转发,会占用机器的带宽和流量。而且如果目标图片太大,比如有几十M ,那么带宽小的服务器肯定是吃不消的,加载速度会特别慢。

同时,我们也得避免自己的接口被别人盗用。

当然也有一些免费的转发服务,但是访问速度很不稳定,比如:

<img src=”https://images.weserv.nl/?url=https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2544866651.jpg" />
3.3.2 防盗链

那现在我们还有什么方法来防御吗?

可能有同学会想到 IP 禁用,针对访问量比较大的 ip,直接封禁掉,但对于访问量不大的网站就不起作用了。

还有同学会想到 User-Agent 防盗链,使用定制的 User-Agent 才能正常访问,但还是无法避免资源转发时自定义 User-Agent,而且这种方式一般只用在 App 上。

其实还有一个大招:URL 参数签名,也就是我们常说的 Token 防盗链

以“又拍云”的 Token 防盗链功能为例:

图片

如上图所示,整个 token 防盗链的实现需要如下几个部分来配合:

  • 客户端:负责发送原始请求给客户端业务服务器以及发送带签名的 URL 给 CDN 节点进行验证;

  • 业务服务器:根据约定的算法生成带 _upt 参数的 URL 返回给客户端;

  • CDN 节点:负责和客户端进行时间、签名校验;

原理也很简单,就是在资源的 url 中带上一个 token,token 中会对当前链接、过期时间等信息进行签名,然后 CDN 节点在处理请求时,先校验 token,如果遇到已过期或者其他异常场景,就禁止访问。

3.4 小结

看完上述的介绍,大家会发现在防盗链的博弈中,没有绝对的优势方。

这是一个不断演进和变化的过程,双方都在不断寻找新的方法来保护或者绕过防护措施。

就比如 token 防盗链就一定安全吗?其实也未必,比如盗链者完全可以定期更新图片链接,而作为防盗链的一方,我们则是可以使用更加完善的流量监控系统。

大家也需要明白,所有的防盗链措施,都是为了提高盗链的成本。

转载至 前端面试宝典 微信小程序 侵删

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
防盗链是指为了阻止其他网站或用户在未经授权的情况下盗用自己网站的资源而采取的一种措施。在Python中,可以通过设置请求头中的"Referer"字段来进行防盗链。 在给定的代码中,通过设置请求头的"referer"字段来模拟请求时的来源页面。这样,被请求的服务器可以根据Referer字段来判断请求的合法性。如果请求的Referer字段与服务器期望的来源页面匹配,则服务器会正常返回请求的资源。否则,服务器可能会返回错误或者拒绝提供资源。 具体来说,在代码中的header字典中设置了"referer"字段的值为"https://www.pearvideo.com/video_1160135",这是一个示例的来源页面链接。根据实际情况,可以将该字段的值设置为合法的来源页面链接。 在请求中,会根据提供的链接获取视频资源的URL,并进行一些拼接替换操作,最终得到视频的真实URL。然后可以使用Python的requests库发送GET请求,获取到视频资源的内容,并进行保存。 总结起来,这段Python代码通过设置请求头的Referer字段来模拟合法的请求来源,从而实现防盗链的效果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python爬虫学习--防盗链](https://blog.csdn.net/weixin_30675247/article/details/95668172)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python--爬虫,了解防盗链-->解决防盗链,解决反反反爬](https://blog.csdn.net/qq_57663276/article/details/127474123)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值