导读
在进一步介绍referer
之前,先提以下几个问题,看你是否都能回答上来。带着这几个问题和疑问去读这篇文章,更有针对性,相信你的收获也会更大。
问题汇总:
1、什么是 referer? 有什么用? 2、怎么设置 referer 白名单? 3、有哪些方式可避开 referer 限制? 4、如何自定义请求的 referer 值?
常见的 http 请求中,header 部分往往都会带有一个referer
字段。如下:
该字段记录了请求来源。以上图为例,请求为:
https://pinpai.1688.com/rpc/imall/channel/recentenroll.json
场景为 IMall 站点(https://imall.1688.com )展示的一个最新入驻信息:
因为是从 IMall 站点页面发出的 http 请求信息,所以referer
的字段信息,就是该站点的 host:https://imall.1688.com
。
但也有一些 http 请求的referer
字段为空,或者干脆不包含这个字段。如:a) 用户直接在地址栏输入 url 链接;b) 从浏览器的收藏夹中直接打开收藏链接;c) 后端代码直接发起 http 请求,未配置 referer 信息;d) 用户的浏览器设置中关闭了携带 referer 信息的功能等。
正常情况下,当前页面加载时发起请求,或用户在页面点击链接发起请求,浏览器会自动在 http 请求 hearder 的referer
字段中,添加当前页面的域名(如上图的场景)。
但若直接在浏览器地址栏中输入该请求 url,因没有来源,也就不会存在referer
字段。如:A 页面中有一个B 页面的跳转链接(https://www.bpage.com
),A 页面的域名是www.apage.com
,那么当用户在A 页面点击了该跳转链接时,跳转链接的请求头(request header)中,携带的referer
信息就是www.apage.com
。
小插曲:
英语好的小伙伴是不是发现了一个问题,
referer
的拼写不对的吧?怎么少了个"r",正确的拼写应该是referrer
。 其实,在制定标准时,提交给官方的字段名就是少了个"r"字母的referer
,神奇的是,所有的人都“默契地”忽略了该单词的拼写错误,因此referer
也就成了官方标准,错了就错了吧,反正也不影响使用。所以屏幕前的小伙伴往后在使用该字段时,一定要注意拼写,是 referer,不是 referrer。
http 请求头 header 中设置了referer
字段,自然有此它的作用。常用的作用有两个,一是统计访问来源,二是设置防盗链。
举个栗子。
在 IMall 站点(imall.1688.com
)页面中嵌入了品牌站的链接(https://pinpai.1688.com
),那么对于品牌站的服务器而言,就可以根据referer
字段来统计所有访问来源中,从 IMall 站点过来的访问量有多少。
首先看下,什么是盗链。
百度百科对"盗链"词条的解释:
服务提供商自己不提供服务的内容,通过技术手段绕过其它有利益的最终用户界面(如广告),直接在自己的网站上向最终用户提供其它服务提供商的服务内容,骗取最终用户的浏览和点击率。受益者不提供资源或提供很少的资源,而真正的服务提供商却得不到任何的收益。
上面这段话比较绕,说的比较官方,可简单理解为:某些 http 请求并不是在任何场景下都可以访问。
我们做个简单的比喻哈。像淘宝上店家售卖的商品图、专业图片网站上的图片,这些都是卖家或者网站的宝贵资源,不能轻易被其他网站利用和展示。比如淘宝商家费了好大劲拍了个好看的模特试穿图,摄影师苦等了个把月才拍到的大漠落日景象,直接被一个第三方网站在他们自己的网站上放了链接展示,这还不得让拍照片的人气的吐血啊。。。
再说了,淘宝平台也不允许这么干,直接把他们的命根子——流量给分摊过去了,淘宝平台是不会允许这种事情发生的。
我们看个示例:
上图是淘宝的一个商品页面,左侧红框中的是商品图片对应的 http 请求:
https://img.alicdn.com/tfscom/i3/TB1GypLh1sAV1JjSZFsYXGdZXXa_M2.SS2_460x460xz.jpg
referer
的值是在*.taobao.com
这个二级域名下:
https://market.m.taobao.com/app/tb-source-app/aiguangjiepc/item/index.html?spm=a21bo.2017.2001.7.5af911d9dPHIsp&itemId=200406358577
那么,如果将 http 请求放在百度首页中访问,会怎样呢?请看下图:
在控制台输入如下语句
location.href='https://img.alicdn.com/tfscom/i3/TB1GypLh1sAV1JjSZFsYXGdZXXa_M2.SS2_460x460xz.jpg'
按下回车后,访问被禁止,这就是淘宝平台设置的防盗链功能。
上面我们看到了盗链的危害,怎么避免盗链呢?答案就是referer
字段。当然了,通过referer
字段来防止盗链只是其中一种方式,像配置nginx
也可以达到防盗链的目的,但本文主要探讨referer
字段的相关知识点,因此就只说明如何通过referer
字段的设置来达到防盗链的目的,其他途径大家可自行搜索,不在本文的讨论范围内~
比如,后台服务器的一个 http 接口,希望其访问来源只能是淘宝站点(https://www.taobao.com )及其二级、三级等子站点,其他来源的 http 请求我们拒绝处理。那么就可以通过设置 http 请求 header 的referer
字段来达到这个目的。
通常,会有个白名单列表来圈定期望来源。比如,在服务器的后台应用(springboot 框架)中,就可以通过配置的方式,限定哪些接口是允许哪些来源的请求访问:
# refer
spring.security.filters.referer-validation.enabled = true
## Spring Security HTTP 安全域名列表,可选值,多值通过","分割,通过"\"作为换行连接符号
spring.security.http.safe.domains = *.taobao.com
一般来说,页面发起的 http 请求,referer
字段的配置,通过前端代码是无法干预的,是由浏览器自主设置添加的,当然了,如果不想携带referer
字段,可在浏览器的设置中关掉即可。
2.2 节中的防盗链功能,也不能全指望referer
字段,对于referer
字段,也是可以伪造的。如下:
HttpURLConnection conn;
conn.setRequestProperty("refer", "http://imall.1688.com");
因此,既然能伪造,也就不能完全信任referer
字段。
Set<String> refererSet = new HashSet<>(Arrays.asList("*.1688.com", "*.alibaba-inc.com"));
String referer = request.getHeader("REFERER");
for (String str : refererSet) {
if (Pattern.matches(str, referer)) {
// ...
}
}
# refer
spring.security.filters.referer-validation.enabled = true
## Spring Security HTTP 安全域名列表,可选值,多值通过","分割,通过"\"作为换行连接符号
spring.security.http.safe.domains = *.taobao.com
对于限定了 referer 范围的请求,在 mock 请求的时候,必须带上特定的 referer,那么,如何操作呢?有以下几种方式。
postman 是一个 chrome 插件,可 mock 多种类型请求,常用的就是 post 和 get。对于限定请求来源的请求,可在 header 中设置 referer 字段。
若添加 referer 时,出现如下提示:
说明设置的 referer 字段未生效,需安装 postman interceptor 插件(详情)。同时设置 interceptor 为 true,如下:
这是一款插件,用于配置特定请求的 referer 字段。配置方式如下:
使用起来也较简单,每个输入的网址右侧有几个按钮:
to
: 表示要访问这个网址from
: 表示请求是从这个网址链接过去3rd
:RegEx
: 以正则方式约束Normal
: 默认方式Custom
: 自定义 refererBlock
: 需阻断的 referer如下图:
这种方式比较简单。
举个栗子就明白了。对于请求:
https://pinpai.1688.com/rpc/imall/channel/recentenroll.json
其要求必须有 header 中的 referer 字段,并且正则匹配如下:
*.1688.com, *.alibaba-inc.com
那么就可以在 1688 网站的任何一个网页,以 imall.1688.com 为例,将任何一个可点击控件的链接值设为该请求。操作如下图:
修改后,点击"首页"就可请求到结果。因为浏览器会默认将当前页面的域名(imall.1688.com)设为 referer 值。