[TOC]

前言

他说我们的忘记密码功能的重置密码链接,会加载第三方统计,这时候带过去的 referer 头部就会将这个页面的 url 带过去,从而暴露了重置密码的 token。

分析

我分析了一下,发现重置密码这个页面,确实在加载第三方统计的时候,referer 头部会将整个 url 当做值带过去, 也就是这些第三方程序是可以在用户进入这个重置密码页面的时候,通过 referer 头部来得到这个重置密码的链接,比如下图:

image.png

危害性

危害性一定程度上是有的,不过当初在做重置密码的时候,本身 token 就存在有效性了,比如半小时。 并且在重置密码的时候,还要输入正确的邮箱,才能重置成功。 所以还是比较安全。
但是总归是一个隐患,所以还是要解决掉。

解决方式

直接不加载第三方统计

这种是最简单的,不加载第三方统计,就不会有暴露问题。 但是有时候我们又需要第三方统计的一些数据来帮助我们了解用户的一些活跃数据和 talking data。所以这个不是最优解。

禁止 referer 头部

最好的方式就是这个页面在加载外部资源的时候,禁止 referer 头部。 后面我们也是用这种方式来处理的。

论页面禁止 referer 的 6 种方式

1. head 标签中添加 meta属性

可以在 head 标签中添加 meta 属性,设置

| name=’referrer’ content=’never’

| | —- |

referer 的 metedata 参数可以设置为以下几种类型的值:

  • never
  • always
  • origin
  • default

如果在文档中插入 meta 标签,并且 name 属性的值为 referrer,浏览器客户端将按照如下步骤处理这个标签:

  1. 如果 meta 标签中没有 content 属性,则终止下面所有操作
  2. 将 content 的值复制给 referrer-policy ,并转换为小写
  3. 检查 content 的值是否为上面 list 中的一个,如果不是,则将值置为 default

接下来浏览器后续发起 http 请求的时候,会按照 content 的值,做出如下反应 (下面 referer-policy 的值即 meta 标签中 content 的值):

  1. 如果 referer-policy 的值为 never:删除 http head 中的 referer
  2. 如果 referer-policy 的值为 default:如果当前页面使用的是 https 协议,而正要加载的资源使用的是普通的 http 协议,则将 http header 中的 referer 置为空
  3. 如果 referer-policy 的值为 origin:只发送 origin 部分
  4. 如果 referer-policy 的值为 always:不改变http header 中的 referer 的值,注意:这种情况下,如果当前页面使用了 https 协议,而要加载的资源使用的是 http 协议,加载资源的请求头中也会携带 referer

    例子

    举个例子,如果你的页面是:

|

| | —- |

那么加载的第三方资源将不会带上 referer 头部:
image.png
而且可以看到请求的 Referrer Policy 变成 no-referrer。
然后如果是换成:

|

| | —- |

就换变成只带 host 域名, 跟 origin 头部几乎一样 (多了最外面一个斜杠)
image.png
然后对应请求的 Referrer Policy 变成 origin:
image.png

兼容性

这个标准还是比较老的,不过通过 can i use meta:referrer 还是可以看到大部分的主流浏览器 (Edge, Firefox, Chrome) 都有支持 (我亲测过了)
image.png

2. 添加ReferrerPolicy属性

添加 meta 标签相当于对文档中的所有链接都取消了 referer ,而 ReferrerPolicy 则更精确的指定了某一个资源的 referer 策略。关于这个策略的定义可以参照 MDN。比如我想只对某一个图片取消referrer,如下编写即可:

web 安全之 - 页面禁用 referer(第三方站点的 referer 头部泄露重置密码链接) - 图6

A 标签也支持这个属性:

兼容性

通过 can i use referrerPolicy, 可以看到除了 IE 和 少部分手机浏览器, 大部分的主流浏览器还是支持的:
image.png

3. 通过 rel=’noreferrer‘

还可以通过标签的 rel 属性来禁止 referer 头部:

|

| | —- |

当然目前兼容的有限, 只支持 , ,

这三个元素:

The noreferrer keyword for the rel attribute of the , , and elements instructs the browser, when navigating to the target resource, to omit the Referer header and otherwise leak no referrer information — and additionally to behave as if the noopener keyword were also specified.
mozilla
developer.mozilla.org/en-US/docs/Web/HTML/Link_types/noreferrer
通过 can i use noreferrer 可以看到支持的浏览器版本:
image.png

4. 代理模式

这个就比较好理解了,把自己的服务器当做代理服务器, 请求先经过自己服务器, 修改referer头, 再反向代理到真正的服务器地址。

5. 外链 通过 iframe 来打开

如果是通过外链的话,那么可以通过 iframe 的方式来打开:

| function open_without_referrer(link){
document.body.appendChild(document.createElement(‘iframe’)).src = ‘javascript:”