Gitee图床失效(防盗链)
<h2 id="问题排查">问题排查</h2><p>今天打开博客园发现,平时记录的一些文章里边放的图标失效了,如下图:</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-04.png" alt="gitee-figure-bed-04.png" loading="lazy"></p>
<p>之前一直用<code>gitee</code>当图床,免费又稳定!今天咋回事?</p>
<p>但是在浏览器打开挂掉的图片,浏览器又是正常展示,这就很神奇了!</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-01.png" alt="gitee-figure-bed-01.png" loading="lazy"></p>
<h3 id="302-moved-temporarily">302 Moved Temporarily</h3>
<p>回到博客园,按下F12键打开开发者工具,看了下这个失效的图标资源的请求。<code>status code</code>是 <code>302 Moved Temporarily</code>,说明请求重定向了。<code>Response Headers</code>中<code>Location</code>为<code>https://assets.gitee.com/favicon.ico</code>,这是重定向后的链接。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-02.png" alt="gitee-figure-bed-02.png" loading="lazy"></p>
<h3 id="403">403</h3>
<p>在网络面板查看这个重定向的链接,点进去看详情,发现<code>status code</code> 为<code>403</code>。</p>
<blockquote>
<p>403错误是一种在网站访问过程中,常见的错误提示,表示资源不可用。服务器理解客户的请求,但拒绝处理它,通常由于服务器上文件或目录的权限设置导致的WEB访问错误。</p>
</blockquote>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-03.png" alt="gitee-figure-bed-03.png" loading="lazy"></p>
<h3 id="referer">Referer</h3>
<p>接着看到<code>Request Headers</code>,其中<code>referer</code>标头引起了我的注意,<code>referer</code>的值为<code>http://www.cnblogs.com/</code>。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-05.png" alt="gitee-figure-bed-05.png" loading="lazy"></p>
<p>MDN对<code>Referer</code>的解释如下:</p>
<blockquote>
<p>Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。</p>
</blockquote>
<p>从上面已知的信息中,我们可以分析出,博客园中失效的图标,经过重定向后,定向到了gitee图标的链接<code>https://assets.gitee.com/favicon.ico</code>,但是这个链接请求被服务器拒绝访问了。</p>
<h2 id="图像防盗链">图像防盗链</h2>
<p>在对比<strong>失效的图标</strong>和<strong>在浏览器可以正常访问的图标</strong>的<code>Request Headers</code>后,我发现,失效的图标请求头中多了个<code>referer</code>标头,是不是意味着,服务端校验了<code>referer</code>请求头,发现请求头不是来源于gitee本站,便拒绝访问呢?</p>
<p>这不是就是常见的图像防盗链处理吗?那什么是防盗链呢?</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-06.png" alt="gitee-figure-bed-06.png" loading="lazy"></p>
<p>咳咳开个玩笑!一句话总结防盗链就是:<strong>防止未经授权使用图像</strong>。</p>
<p>试想一下,A网站有很多图像资源供给用户访问和下载,B网站把A网站的图像资源链接放到自己网站上。这样既能够让用户浏览到A网站的图像资源,又没有消耗自己服务器的流量。这不是白嫖嘛?</p>
<ul>
<li>A网站图像资源</li>
</ul>
<pre><code>https://a.com/icon-kobe.png
</code></pre>
<ul>
<li>B网站盗用A网站的图像链接,用户访问时消耗的是A网站的服务流量</li>
</ul>
<pre><code class="language-html"><img src="https://a.com/icon-kobe.png" alt="this is kobe icon"/>
</code></pre>
<p>A网站岂能容忍,为了防止他人未经授权使用图像,对图像资源进行了防盗链处理。</p>
<h2 id="防盗链的实现方法">防盗链的实现方法</h2>
<p>经过刚才的分析,不难得出防盗链的实现原理:服务端判断访问来源是否来自本站或白名单站点,当访问来源不符合这些条件时,服务器便可拒绝其操作。</p>
<p>而识别访问来源,可通过请求头中的<code>Referer</code>标头字段去区分。当然只要是能够识别访问来源是否为本站或白名单站点的方法,都能够用来实现防盗链。更多实现方法可参考这篇文章《如何选择适合自己网站的防盗链》 - 掘金</p>
<p>Nginx常用来做静态资源的代理转发,我们可以用Nginx提供的一些配置参数和规则去限制实现防盗链的功能。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-07.png" alt="gitee-figure-bed-07.png" loading="lazy"></p>
<p>查阅文档之后,了解到<code>ngx_http_referer_module</code>这个模块可以让我们实现防盗链的功能。</p>
<ul>
<li>Example Configuration</li>
</ul>
<pre><code>valid_referer none blocked server_names
*.example.com example.* www.example.org/galleries/
~\.google\.;
if ($invalid_referer) {
return 403;
}
</code></pre>
<h3 id="只放行指定站点">只放行指定站点</h3>
<p>如下是一个配置案例,只放行<code>referer</code>标头为<code>*.zzcyes.com</code>的站点。更多配置请查阅文档</p>
<pre><code>location /images/ {
valid_referer *.zzcyes.com;
if ($invalid_referer) {
rewrite ^/ http://www.zzcyes.com/wangwangwang.jpg;
}
}
}
</code></pre>
<p>假设我们需要访问的图片为24号紫金球衣<code>http://www.zzcyes.com/images/icon/icon-kobe.png</code></p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-10.png" alt="gitee-figure-bed-10.png" loading="lazy"></p>
<p>如果访问源不是<code>*.zzcyes.com</code>,则重定向到狗子的照片</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-11.jpg" alt="gitee-figure-bed-11.jpg" loading="lazy"></p>
<p>接下进行验证,在浏览器输入图片链接,可以看到,浏览器直接重定向到了狗子的照片。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-08.gif" alt="gitee-figure-bed-08.gif" loading="lazy"></p>
<h3 id="放行空referer和指定站点">放行空referer和指定站点</h3>
<p>放行空<code>referer</code>标头和<code>referer</code>标头为<code>*.zzcyes.com</code>的站点。</p>
<pre><code>location /images/ {
valid_referer valid_referer none*.zzcyes.com;
if ($invalid_referer) {
rewrite ^/ http://www.zzcyes.com/wangwangwang.jpg;
}
}
}
</code></pre>
<p>在浏览器中输入图片链接直接访问,是能正常显示图片的,因为浏览器不会在请求头添加<code>referer</code>标头。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-12.png" alt="gitee-figure-bed-12.png" loading="lazy"></p>
<p>而在第三方站点访问图片时,<code>referer</code>标头的值为第三站点,根据nginx配置的规则,会重定向到狗子的照片。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-13.png" alt="gitee-figure-bed-13.png" loading="lazy"></p>
<h2 id="防盗链的破解方法-只放行指定站点">防盗链的破解方法: 只放行指定站点</h2>
<p>在前边的案例中,nginx只配置了<strong>只放行指定站点</strong>这一规则,那么只有在指定站点才能够访问到图像资源。</p>
<p>但在一般情况下,网站是不会这样去限制访问来源必须是本站或者指点站点的。</p>
<p>试想有这么一个场景:用户在浏览器的搜索栏中输入网站的图像资源。</p>
<ul>
<li>
<p>期望:浏览器能够正常显示图像资源的。</p>
</li>
<li>
<p>结果:无法正常展示(服务端只放行指定站点,对于那些非指定站点和空referer标头,都会被服务段拒绝访问或者重定向。)</p>
</li>
</ul>
<p>这样用户期望看到的图像资源无法正常展示,这样不合常理。</p>
<p>接下来的破解均以访问科比24号紫金球衣<code>http://www.zzcyes.com/images/icon/icon-kobe.png</code>的图片为例,nginx配置如下:</p>
<pre><code>location /images/ {
valid_referer valid_referer*.zzcyes.com;
if ($invalid_referer) {
rewrite ^/ http://www.zzcyes.com/wangwangwang.jpg;
}
}
}
</code></pre>
<p>用vscode起了一个本地服务<code>http://127.0.0.1:5500/index.html</code>,去加载球衣图片资源。</p>
<pre><code class="language-html"><!-- index.html -->
<img src="http://www.zzcyes.com/images/icon/icon-kobe.png" alt="this is kobe icon"/>
</code></pre>
<p>因为nginx配置的规则只允许放行<code>*.zzcyes.com</code>,本地起的服务加载图像资源失败,会重定向到狗子的照片。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-13.png" alt="gitee-figure-bed-13.png" loading="lazy"></p>
<p>对于只放行指定站点这一规则,我们可以从伪造referer标头入手。因为服务端只是验证referer标头是否是指定站点,那么只要我们伪造请求的referer为相对应的站点,便可破解防盗链了。</p>
<h3 id="谷歌浏览器插件">谷歌浏览器插件</h3>
<p>谷歌应用商店有很多这类的插件,这里推荐<strong>Referer Control</strong>。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-19.png" alt="gitee-figure-bed-19.png" loading="lazy"></p>
<p>我用这个插件配置了一个自定义规则,用<code>http://www.zzcyes.com</code>作为访问来源的地址,即请求头的referer标头的值为<code>http://www.zzcyes.com</code>。</p>
<p><img src="https://www.zzcyes.com/master/images/gitee-figure-bed-20.png" alt="gitee-figure-bed-20.png" loading="lazy"></p>
<p>接着,刷新本地服务启动的<code>http://127.0.0.1:5500/index.html</code>页面,可以看到,球衣图片加载出来了,并且Referer标头被篡改成了<code>http://www.zzcyes.com</code>。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-21.png" alt="gitee-figure-bed-21.png" loading="lazy"></p>
<h3 id="终端访问下载">终端访问下载</h3>
<p>在终端输入curl语句,并设置referer标头为<code>http://www.zzcyes.com</code>,这样我们可以正常下载图像资源。</p>
<pre><code class="language-shell">curl -o icon-kobe.png -H "referer":"http://www.zzcyes.com"http://www.zzcyes.com/images/icon/icon-kobe.png
</code></pre>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-22.png" alt="gitee-figure-bed-22.png" loading="lazy"></p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-23.png" alt="gitee-figure-bed-23.png" loading="lazy"></p>
<h2 id="防盗链的破解方法-放行空referer和指定站点">防盗链的破解方法: 放行空referer和指定站点</h2>
<p>在nginx配置<strong>放行空referer和指定站点</strong>的这一规则,是实现防盗链的常用方式。</p>
<p>如果想快速验证网站的图像资源是否采用了这种防盗链的实现规则,可以把图像资源的链接输入进浏览器的搜索栏中,回车后如果图片能正常显示,说明服务器是允许放行空的referer标头的这类请求。</p>
<p>要破解这类防盗链,可以从服务段允许放行空referer标头入手了。</p>
<p>接下来还是以访问科比24号紫金球衣<code>http://www.zzcyes.com/images/icon/icon-kobe.png</code>的图片为例,nginx配置如下:</p>
<pre><code>location /images/ {
valid_referer valid_referer none*.zzcyes.com;
if ($invalid_referer) {
rewrite ^/ http://www.zzcyes.com/wangwangwang.jpg;
}
}
}
</code></pre>
<h3 id="浏览器直接输入url">浏览器直接输入url</h3>
<p>浏览器输入图片地址后回车,是能正常显示图片的。因为在浏览器直接输入地址发起请求,请求头不携带referer标头,这样一来就能通过服务器的校验了。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-14.png" alt="gitee-figure-bed-14.png" loading="lazy"></p>
<h3 id="终端访问下载-1">终端访问下载</h3>
<p>同样,在终端输入curl语句,这时请求头也是不携带referer标头的,我们可以正常下载图像资源。</p>
<pre><code class="language-shell">curl -o icon-kobe.png http://www.zzcyes.com/images/icon/icon-kobe.png
</code></pre>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-15.png" alt="gitee-figure-bed-15.png" loading="lazy"></p>
<h3 id="http升级为https仅限请求页面为非安全协议">HTTP升级为HTTPS(仅限请求页面为非安全协议)</h3>
<p>为了方便对比,这里用vscode的liveServer插件起了一个HTTP服务和一个HTTPS服务。</p>
<pre><code class="language-html"><!-- index.html -->
<img src="http://www.zzcyes.com/images/icon/icon-kobe.png" />
</code></pre>
<ul>
<li>HTTP</li>
</ul>
<p>可以看到,请求的图像资源携带的referer标头为<code>http://127.0.0.1:5500/</code>,与nginx配置的<code>*.zzcyes.com</code>不匹配,因此重定向到狗子的图片了。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-16.png" alt="gitee-figure-bed-16.png" loading="lazy"></p>
<ul>
<li>HTTPS</li>
</ul>
<p>可以看到,请求的图像资源携带的referer标头为<code>https://127.0.0.1:5500/</code>,与nginx配置的<code>*.zzcyes.com</code>不匹配,但是图片资源却成功返回了。</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-17.png" alt="gitee-figure-bed-17.png" loading="lazy"></p>
<p>带着这个疑惑查了下MDN的资料:</p>
<blockquote>
<p>在以下两种情况下,Referer 不会被发送:</p>
<ul>
<li>来源页面采用的协议为表示本地文件的 "file" 或者 "data" URI;</li>
<li>当前请求页面采用的是非安全协议,而来源页面采用的是安全协议(HTTPS)。</li>
</ul>
</blockquote>
<p>这里请求的资源图片<code>http://www.zzcyes.com/images/icon/icon-kobe.png</code>是非安全协议,来源页面是<code>https://127.0.0.1:5500/index.html</code>安全协议。</p>
<p>也就是说,其实服务端接收到的请求,请求头中并不会携带Referer标头!所以,我们能利用安全协议的页面去访问非安全协议页面中的图片。</p>
<p>那么,当来源页面和请求页面均是HTTPS协议时,会有什么效果呢?根据MDN文档描述,Referer标头是能够正常发送的,于是我去HTTPS服务的nginx配置了下相同的规则,允许<strong>放行空referer和referer标头为*.zzcyes.com站点</strong>,然后再用HTTPS协议的页面去请求图像资源!</p>
<p><img src="https://www.zzcyes.com/images/gitee-figure-bed-18.png" alt="gitee-figure-bed-18.png" loading="lazy"></p>
<p>可以看到,这里图片资源已经不能正常访问了,重定向到狗子的照片了。也就说Referer标头是能够被服务端接受到的,并且nginx配置的Referer校验规则生效了,拒绝放行非*.zzcyes.com站点的请求,并重定向到狗子的照片了。</p>
<h2 id="文章链接">文章链接</h2>
<ul>
<li>
<p>你已经是个成熟的前端了,应该学会破解防盗链了 - 掘金</p>
</li>
<li>
<p>如何选择适合自己网站的防盗链 - 掘金</p>
</li>
<li>
<p>Module ngx_http_referer_module</p>
</li>
</ul><br><br>
来源:https://www.cnblogs.com/zzcyeah/p/anti-leech.html
頁:
[1]