HTTP请求的头信息里面,Referer是一个常见字段,提供访问来源的信息。很多开发者知道这个字段,但是说不清它的具有细节。本文详细介绍该字段。
一、Referer的含义
现实生活中,购买服务或加入会员的时候,往往要求提供信息:“你是从哪里知道的我们?”,这叫做引荐人(referer),谁引荐了你?对公司来说很,这是很有用的信息。互联网也是一样,你不会无缘无故访问一个网页,总会有人告诉你,可以去那里看看。服务器也想知道,你的“引荐人”是谁?
HTTP协议在请求(request)的头部信息里,设计了一个Referer字段,给出“引荐网页”的URL。
比如说我们在谷歌浏览器上,从百度搜索关键字,然后跳转到我们搜索的网站,那么它的Referer就是百度的搜索链接。百度链接比较长,待上课关键之类的。如下图:
这里特别注意:Referer请求头可能会暴露用户的浏览历史、涉及到用户的隐私问题。
二、Referrer-policy的值及用法
Referrer-policy可以一定程度上防御csrf漏洞
目前很多网站的防盗链机制都是用头部定义Referrer来判断是都盗链。其实这个很容易破解,自己在请求时加上Referrer头部就行。
在哪些情况下会设置引用头呢?一般来说,加载一个HTML页面之后,本HTML页面里面的JavaScript文件,CSS文件,画面文件都会设置Referrer。然后,点击这个HTML页面里的链接,跳转其他页面时,也会设置Referrer。
Referrer-policy的8个值:
- no-referrer:整个referer首部会被移除,访问来源信息不随着请求一起发送。通俗易懂的来说就是所有请求不发送Referrer。
- no-referrer-when-downgrade:在没有指定任意策略的情况下用户代理的默认行为。在同等级安全级别的情况下,引用页面的地址会被发送(HTTPS->HTTPS),但是在降级的情况下不会被发送(HTTPS->HTTP)。
- origin:任意情况下,仅发送文件的源作为引用地址。源信息包括访问协议和域名。例如:https://example.com/page.html会将https://example.com/作为引用地址。
- origin-when-cross-origin:对于同源的请求,会发送完整的URL作为引用地址,但是对于非同源请求仅发送文件的源。
- same-origin:对于同源的请求会发送引用地址,但是对于非同源请求则不会发送引用地址信息。例如:如果设置成same-origin,那么aaa.com引用bbb.com的资源,就不会发送Referrer。
这里同源的意思是指同一个域名且同一协议。
- strict-origin:再同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS),但是在降级的情况下不会发送(HTTPS->HTTP)。
- strict-origin-when-cross-origin:对于同源的请求,会发送完整的URL作为引用地址;再同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS);在降级的情况下不发送此首部(HTTPS->HTTP)。
- unsafe-url:无论是同源请求还是非同源请求,都发送完整的URL(移除参数信息之后)作为引用地址。(最不安全)。
三、Referer的设置
1.在HTML里设置meta
<meta name="referrer" content="origin">
如下图:
或者用、、、<iframe>、<script>、<link>元素上的referrerpolicy属性为其设置独立的请求策略。如下图:
<script src='/javascripts/test.js' referrerpolicy="no-referrer"></script>
未加link元素的referrerpolicy属性会出现下图所示:
四、防盗链
1.防盗链的工作原理
通过referer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以追踪到显示它的网页地址,一旦检测到来源不是本站,即进行阻止或者返回指定的页面。
2.如何绕过图片防盗链
现在很多网站是如何利用Referer来进行防图片盗链的呢?
其实是有三种情况下允许引用图片:
- 本网站
- 无Referer信息情况。(服务器认为是从浏览器直接访问的图片URL,所以这种情况下是能正常访问)
- 授权的网址
通常情况下我们只能从情况2入手,通过设置Referer为空进行绕过防盗链。
(1)利用https网站盗链http资源网站,referer不会发送
先利用openssl生成自签名证书(可以参考这个https://github.com/zxl925768661/Blog/tree/main/HTTP%E7%9B%B8%E5%85%B3/Demos/referer/demo03) )
只适用于旧版本的浏览器,https降为http 是一种非常不安全的行为,该操作浏览器会自动禁止。虽然降级失败但是可以成功访问/src/img/1.jpg.因为referer为空且白名单命中了192.168.0.103:8080 字段。
whiteList.indexof(referHostName) == 1 ,返回了正确的图
设置meta
<meta name="referrer" content="no-referrer" />
(2)利用iframe伪造请求Referer
可以参考(如何绕开referrer防盗链 - 掘金)这个网址
结果如下:
(3)利用XMLHTTPRequest
XMLHttpRequest中setRequestHeader方法,用于请求头添加或修改字段。
// 通过ajax下载图片
function loadImage(uri) {
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.onload = function() {
resolve(xhr.response);
};
xhr.open("GET", uri, true);
// 通过setRequestHeader设置header不会生效
// 会提示 Refused to set unsafe header "Referer"
xhr.setRequestHeader("Referer", "");
xhr.send();
});
}
// 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
function handleBlob(blob) {
let reader = new FileReader();
reader.onload = function(evt) {
let img = document.createElement('img');
img.src = evt.target.result;
document.getElementById('container').appendChild(img)
};
reader.readAsDataURL(blob);
}
const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
loadImage(imgSrc).then(blob => {
handleBlob(blob);
});
上述代码运行时会发现控制台提示错误:
Refused to set unsafe header "Referer"
可以看见setRequestHeader设置referer响应头是无效的,这是由于浏览器为了安全起见,无法手动设置部分保留字段,不幸的是Referer恰好就是保留字段之一。
版权归原作者 流年ꦿ 所有, 如有侵权,请联系我们删除。