HTTP Referer详解及Referer控制
什么是HTTPReferer
referer的意思简言之,HTTPReferer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。
比如在一个网页里面插入一个超链接,链接到其他的网页,那么当点击这个超链接从而链接到另外一个页面的时候,相当于浏览器向web服务器发送了一个http请求,对于另外一个页面而言,这个referer就是上一个页面的URL,而对于从地址栏里面直接输入URL或者是刷新网页的方式,则referer=null,通过设置这个referer可以防止盗链的问题
例如从我主页上链接到一个朋友那里,他的服务器就能够从HTTPReferer中统计出每天有多少用户点击我主页上的链接访问他的网站。
Referer其实应该是英文单词Referrer,不过拼错的人太多了,所以编写标准的人也就将错就错了。
Referer有时也被用作防盗链
即下载时判断来源地址是不是在网站域名之内,否则就不能下载或显示,很多网站,如天涯就是通过Referer页面来判断用户是否能够下载图片.
当然,对于某些恶意用户,也可能伪造Referer来获得某些权限,在设计网站时要考虑到这个问题.
还可用做电子商务网站的安全,在提交信用卡等重要信息的页面用referer来判断上一页是不是自己的网站,如果不是,可能是黑客用自己写的一个表单,来提交,为了能跳过你上一页里的javascript的验证等目的。
但是注意不要把Rerferer用在身份验证或者其他非常重要的检查上,因为Rerferer非常容易在客户端被改变
虽然Referer并不可靠,但用来防止图片盗链还是足够的,毕竟不是每个人都会修改客户端的配置。实现一般都是通过apache的配置文件,首先设置允许访问的地址:
#只允许来自domain.com的访问,图片可能就放置在domain.com网站的页面上 SetEnvIfNoCaseReferer“^http://www.domain.com/”local_ref #直接通过地址访问 SetEnvIfReferer“^$”local_ref
然后再规定被标记了的访问才被允许:
OrderAllow,Deny Allowfromenv=local_ref
或者
OrderDeny,Allow Denyfromall Allowfromenv=local_ref
哪些情况下无法获得上一页referrer信息
直接在浏览器地址栏中输入地址;
使用location.reload()刷新(location.href或者location.replace()刷新有信息);
在微信对话框中,点击链接进入微信自身的浏览器;
扫码进入QQ或者微信的浏览器;
直接新窗口打开一个页面;2017.8.3更新新版本Chrome测试,新窗口页面依然有document.referrer
从https的网站直接进入一个http协议的网站(Chrome下亲测);
a标签设置rel="noreferrer"(兼容IE7+);
meta标签来控制不让浏览器发送referer;
例如:
使用RefererMeta标签控制referer
使用场景
在某些情况下,出于一些原因,网站想要控制页面发送给server的referer信息的情况下,可以使用这一referermetadata参数。
隐私
社交网站一般都会有用户个人页面,这些页面中用户都有可能添加一些外网的链接,而社交网站有可能不希望在用户点击了这些链接的时候,泄露用户页面的URL,因为这些URL中可能包含一些敏感信息。当然,有些社交网站可能只想在referer中提供一个hostname,而不是完整的URL信息。
安全
有些使用了https的网站,可能在URL中使用一个参数(sid等)来作为用户身份凭证,而又需要引入其他https网站的资源,这种情况下,网站肯定不希望泄露用户的身份凭证信息。
Object-CapabilityDiscipline
有些网站遵循Object-CapabilityDiscipline,而referer刚好与这一策略相悖,所以,网站能够控制refeer将对Object-CapabilityDiscipline很有利。
技术细节
referer的metedata参数可以设置为以下几种类型的值:
never
always
origin
default
如果在文档中插入meta标签,并且name属性的值为referer,浏览器客户端将按照如下步骤处理这个标签:
1.如果meta标签中没有content属性,则终止下面所有操作
2.将content的值复制给referrer-policy,并转换为小写
3.检查content的值是否为上面list中的一个,如果不是,则将值置为default
上述步骤之后,浏览器后续发起http请求的时候,会按照content的值,做出如下反应(下面referer-policy的值即meta标签中content的值):
1.如果referer-policy的值为never:删除httphead中的referer;
2.如果referer-policy的值为default:如果当前页面使用的是https协议,而正要加载的资源使用的是普通的http协议,则将httpheader中的referer置为空;
3.如果referer-policy的值为origin:只发送origin部分;
4.如果referer-policy的值为always:不改变httpheader中的referer的值,注意:这种情况下,如果当前页面使用了https协议,而要加载的资源使用的是http协议,加载资源的请求头中也会携带referer。
例子
如果页面中包含了如下meta标签,所有从当前页面中发起的请求将不会携带referer:
如果页面中包含了如下meta标签,则从当前页面中发起的http请求将只携带origin部分(注:根据原文中的语境,我理解这里的origin是包含了schema和hostname的部分url,不包含path等后面的其他url部分),而不是完整的URL:
注意:在使用本文中所述的meta标签的时候,浏览器原有的referer策略将被打破,比如从http协议的页面跳转到https的页面的时候,如果设置了适当的值,也会携带referer。
其他问题
这与rel=noreferer有什么关系呢?可能rel=noreferer会覆盖掉本文中的meta标签所设置的值。也就是功能覆盖。
origin信息不是一个完整的url,所以浏览器客户端估计会在origin后面加一个/来作为path部分。
如果origin是唯一的,会发生什么情况呢?估计referer会被忽略。