浅析HTTP的Referer含义理解、Referer作用(记录访问来源、防盗链、防止恶意请求)、Referrer Policy引用策略的9个值及设置用法、什么情况会导致空Referer
HTTP 请求的头信息里面,Referer
是一个常见字段,提供访问来源的信息。很多开发者知道这个字段,但是说不清它的具体细节。本文详细介绍该字段。
一、Referer 的含义
现实生活中,购买服务或加入会员的时候,往往要求提供信息:"你从哪里知道了我们?",这叫做引荐人(referrer),谁引荐了你?对于公司来说,这是很有用的信息。互联网也是一样,你不会无缘无故访问一个网页,总是有人告诉你,可以去那里看看。服务器也想知道,你的"引荐人"是谁?
HTTP 协议在请求(request)的头信息里面,设计了一个 Referer
字段,给出"引荐网页"的 URL。
Referer 是 HTTP 请求header
的一部分,当浏览器向服务器发送请求的时候,头信息里有包含 Referer 。比如我在www.google.com 里有一个www.baidu.com
链接,那么点击这个www.baidu.com
,它的header
信息里就有:Referer=http://www.google.com,由此可以看出来:它就是表示一个来源。
比如我从百度搜索关键字,然后跳转到我们网站,那么其 Referer 就是百度的搜索链接,百度链接比较长,带上了关键字之类的,如果是谷歌的话,就只有谷歌的网址,没有关键字那些。
这个字段是可选的。客户端发送请求的时候,可以自主决定是否加上该字段。
需要注意的是,这个字段的拼写是错的。Referer
的正确拼写是 Referrer
,但是写入标准的时候,不知为何,没人发现少了一个字母 r
。标准定案以后,只能将错就错,所有头信息的该字段都一律错误拼写成 Referer
。
二、Referer 的常见作用
Referer
字段实际上告诉了服务器,用户在访问当前资源之前的位置,这往往可以用来用户跟踪。
1、用户行为日志记录访问来源:这个就不多说了。
2、另一个典型的应用是:防盗链
比如有些网站不允许图片外链,只有自家的网站才能显示图片,外部网站加载图片就会报错。它的实现就是基于Referer
字段,如果该字段的网址是自家网址,就放行。
刚刚前面有提到一个小 demo,我在www.google.com里有一个www.baidu.com
链接,那么点击这个www.baidu.com
,它的header信息里就有:Referer=http://www.google.com,那么可以利用这个来防止盗链了,比如我只允许我自己的网站访问我自己的图片服务器,那我的域名是www.google.com
,那么图片服务器每次取到Referer来判断一下是不是我自己的域名www.google.com
,如果是就继续访问,不是就拦截。这是不是就达到防盗链的效果了呢。
如何处理:将http请求发给服务器后,如果服务器要求必须是某个地址或者某几个地址才能访问,而你发送的referer不符合他的要求,就会拦截或者跳转到他要求的地址,然后再通过这个地址进行访问。
对于某些恶意用户,也可能伪造Referer来获得某些权限,在设计网站时要考虑到这个问题。比如做电子商务网站的安全,在提交信用卡等重要信息的页面用 referer 来判断上一页是不是自己的网站,如果不是,可能是黑客用自己写的一个表单来提交,为了能跳过你上一页里的 javascript 的验证等目的。但是注意不要把Rerferer用在身份验证或者其他非常重要的检查上,因为Rerferer非常容易在客户端被改变。
3、防止恶意请求
比如静态请求是.html结尾的,动态请求是.shtml,那么所有的*.shtml请求,必须 Referer为我自己的网站才可以访问,这就是Referer的作用。
4、由于涉及隐私,很多时候不适合发送Referer
字段。
这里举两个例子,都不适合暴露 URL。一个是功能 URL,即有的 URL 不要登录,可以访问,就能直接完成密码重置、邮件退订等功能。另一个是内网 URL,不希望外部用户知道内网有这样的地址。Referer
字段很可能把这些 URL 暴露出去。
此外,还有一种特殊情况,需要定制Referer
字段。比如社交网站上,用户在对话中提到某个网址。这时,不希望暴露用户所在的原始网址,但是可以暴露社交网站的域名,让对方知道,是我贡献了你的流量。
(1)隐私:社交网站一般都会有用户个人页面,这些页面中用户都有可能添加一些外网的链接,而社交网站有可能不希望在用户点击了这些链接的时候,泄露用户页面的 URL ,因为这些 URL 中可能包含一些敏感信息。当然,有些社交网站可能只想在 referer 中提供一个 hostname,而不是完整的 URL 信息。
(2)安全:有些使用了 https 的网站,可能在 URL 中使用一个参数(sid 等)来作为用户身份凭证,而又需要引入其他 https 网站的资源,这种情况下,网站肯定不希望泄露用户的身份凭证信息。
三、rel
属性
由于上一节的原因,浏览器提供一系列手段,允许改变默认的 Referer
行为。对于用户来说,可以改变浏览器本身的全局设置,也可以安装浏览器扩展。这里就不详细介绍了。
对于开发者来说,rel="noreferrer"
属性是最简单的一种方法。<a>
、<area>
和<form>
三个标签可以使用这个属性,一旦使用,该元素就不会发送Referer
字段。
<a href="..." rel="noreferrer" target="_blank">xxx</a>
上面链接点击产生的 HTTP 请求,不会带有Referer
字段。注意,rel="noreferrer"
采用的是正确的拼写。
四、Referrer Policy 的值及用法
1、什么是引用策略(Referrer Policy)?
引用策略就是从一个文档发出请求时,是否在请求头部定义 Referrer 的设置。
目前很多网站的防盗链机制都是用头部定义 Referrer 来判断是否是盗链。其实这个很容易破解,自己在请求时加上 Referrer 头部就行。
在哪些情况下会设置引用头呢?一般来说,加载一个 HTML 页面之后,本 HTML 页面里的 JavaScript 文件,CSS 文件,画面文件都会设置 Referrer。然后,点击这个 HTML 页面里的链接,跳转其它画面时,也会设置 Referrer。
2、Referrer Policy 的 9 个取值:
rel
属性只能定制单个元素的Referer
行为,而且选择比较少,只能发送或不发送。W3C 为此制定了更强大的 Referrer Policy。Referrer Policy 可以设定9个值。
(1)空字符串 - 默认值:一般浏览器的默认值是 no-referrer-when-downgrade
(2)no-referrer - 所有请求不发送 referrer。
(3)no-referrer-when-downgrade:当请求安全级别下降时不发送 referrer。目前,只有一种情况会发生安全级别下降,即从 HTTPS 到 HTTP。HTTPS 到 HTTP 的资源引用和链接跳转都不会发送 referrer。
(4)same-origin:对于同源的链接和引用,会发送referrer,其他的不会。同源的意思是指同一个域名且同一协议。如果设置成 same-origin,那么 aaa.com 引用 bbb.com 的资源,不会发送 referrer。子域名也不是同一个域名,aaa.com 引用 test.aaa.com 的资源,不会发送 referrer。
(5)origin:会发送 referrer,但只会发送源信息。源信息包括访问协议和域名。
(6)strict-origin:这个相当于 origin 和 no-referrer-when-downgrade 的 AND 合体。即在安全级别下降时不发送 referrer;安全级别未下降时发送源信息。
注意:这个是新加的标准,有些浏览器可能还不支持。
(7)origin-when-cross-origin:这个相当于 origin 和 same-origin 的 OR 合体。同源的链接和引用,会发送完全的 referrer 信息;但非同源链接和引用时,只发送源信息。
(8)strict-origin-when-cross-origin:这个比较复杂,同源的链接和引用,会发送 referrer。安全级别下降时不发送 referrer。其它情况下发送源信息。
注意:这个是新加的标准,有些浏览器可能还不支持。
(9)unsafe-url:无论是否发生协议降级,无论是本站链接还是站外链接,统统都发送 Referrer 信息。正如其名,这是最宽松而最不安全的策略。
3、Referrer Policy 的设置方法:
(1)HTTP 头信息:服务器发送网页的时候,通过 http 响应头中的 Referrer-Policy 字段告诉浏览器
Content-Security-Policy: referrer no-referrer|no-referrer-when-downgrade|origin|origin-when-cross-origin|unsafe-url;
(2)<meta>
标签:也可以使用<meta>
标签,在网页头部设置。
<meta name="referrer" content="no-referrer|no-referrer-when-downgrade|origin|origin-when-crossorigin|unsafe-url">
(3)referrerpolicy
属性:<a>
、<area>
、<img>
、<iframe>
和<link>
标签,可以设置referrerpolicy
属性。
<a href="..." referrerpolicy="origin" target="_blank">xxx</a>
4、退出页面重定向
还有一种比较老式的技巧,但是非常有效,可以隐藏掉原始网址,谷歌和 Facebook 都在使用这种方法。
链接的时候,不要直接跳转,而是通过一个重定向网址,就像下面这样。
<a href="/exit.php?url=http%3A%2F%2Fexample.com">Example.com</a>
上面网址中,先跳转到/exit.php
,然后再跳转到目标网址。这时,Referer
字段就不会包含原始网址。
五、空Referer是怎么回事
空Referer是指Referer头部的内容为空,或者,一个HTTP 请求头中根本不包含Referer,那么什么时候HTTP请求会不包含Referer字段呢?
根据Referer的定义,它的作用是指示一个请求是从哪里链接过来,那么当一个请求并不是由链接触发产生的,那么自然也就不需要指定这个请求的链接来源。
比如,直接在浏览器的地址栏中输入一个资源的URL地址,那么这种请求是不会包含Referer字段的,因为这是一个“凭空产生”的HTTP请求,并不是从一个地方链接过去的。
那么在防盗链设置中,允许空Referer和不允许空Referer有什么区别?
允许Referer为空,意味着你允许比如浏览器直接访问,就是空。
拒绝空的 Referer ,比如我的www.sojson.com
的静态资源都是拒绝空的Referer
的,那么当我访问我的一个图片时,就访问不了,直接报 403 拒绝访问。
最后我们了解一下哪些情况下无法获得上一页 referrer 信息:
(1)直接在浏览器地址栏中输入地址;
(2)使用 location.reload() 刷新( location.href 或者 location.replace() 刷新有信息);
(3)在微信对话框中,点击链接进入微信自身的浏览器;
(4)扫码进入QQ或者微信的浏览器;
(5)直接新窗口打开一个页面;
(6)a标签设置 rel="noreferrer"
(7)meta标签来控制不让浏览器发送referer;例如:<meta content="never" name="referrer">