HTTP Referer 的最佳实践

2024-09-24 pv

关于 HTTP Referer,阮一峰老师曾经写过一篇很简洁的文章:HTTP Referer 教程 - 阮一峰的网络日志🔗

这是一个看似简单,内涵却很丰富的概念。可以用于站点分析、安全策略和个性化等场景。

今天之所以打算谈谈这个字段,是因为自己在使用 Google Analytics 或者 Umami 这种站点分析工具的时候,发现有类似 Referrers 这种数据。

借此我们可以分析流量来源及其分布。

1. HTTP Referer 含义

Referer 是 HTTP 请求头字段里的一种,包含当前请求页来源页的地址,注意,是当前页的来源页,另外,这是一个可选标头。

与 POSIX 中 CREAT 的经典错误一样,它是 referrer 的错误拼写,但当时写入 HTTP 规范的时候并没有被发现,于是为了保证前向兼容,只好将错就错。

伴随 Referer 字段,还有两个相关概念。

  • Referrer-Policy
  • document.referrer

Referrer-Policy 用于控制哪些访问来源信息会放在 Referer 中一起发送。

document.referrer 则是 document 对象中的一个可读字段,可以通过 JavaScript 获取到当前页的来源页。

2. HTTP Referer 使用场景

Referer 请求头的使用通常发生在下列场景中:

  • 用户点击链接跳转
  • 浏览器请求图片、iframe、脚本或其他资源

而下面两种情况则不会:

  • 来源页面采用的协议为本地的文件,如 file:// 或 data://
  • 当前请求采用的是非安全协议,而来源页采用的是安全协议(HTTPS)

毫无疑问,Referer 字段会暴露部分隐私。

如上图所示,借助该字段,网站所有者可以在服务端进行流量来源统计。

另外,有些网站不允许图片外链访问,只有自家网页才可以,其内部实现也是借助 Referer 字段,一旦发现请求来自外部站点,直接拒绝。

对于改变默认的 Referer 设置,如果只需要选择是否发送,对于 <a>、<area> 或者 <link> 元素,可将 rel 属性设置为 noreferrer ,例如:

<a href="http://example.com" rel="noreferrer">…</a>

而如果要精确控制哪些来源网页信息可用于当前请求,则需要设置 Referer-Policy

Policy 主要分为 8 种情况。参考自:Referrer-Policy - HTTP | MDN🔗

no-referrer🔗

整个 Referer🔗 首部会被移除。访问来源信息不随着请求一起发送。

no-referrer-when-downgrade🔗

在同等安全级别或安全级别提升的情况下(HTTP→HTTP、HTTP→HTTPS、HTTPS→HTTPS),在 Referer🔗 中发送 来源🔗、路径和查询字符串。而在目标的安全级别下降的情况下(HTTPS→HTTP、HTTPS→file)则不发送 Referer🔗 标头。

origin🔗

仅在 Referer🔗 标头中发送 来源🔗。例如 https://example.com/page.html 文档会将 https://example.com/ 作为引用地址。

origin-when-cross-origin🔗

对于同源的请求,会发送完整的 URL 作为引用地址,但是对于非同源请求仅发送文件的源。

same-origin🔗

对于 同源的请求🔗 同源的请求发送引用地址,但是对于非同源请求则不发送引用地址信息。

strict-origin🔗

在同等安全级别的情况下,发送文件的源作为引用地址 (HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。

strict-origin-when-cross-origin🔗(默认值)

对于同源的请求,发送来源、路径以及查询字符串。对于在相同安全级别的情况下(HTTPS→HTTPS)的跨源请求,仅发送来源。在目标的安全级别下降的情况下(HTTPS→HTTP)则不发送 Referer🔗 标头。

unsafe-url🔗

无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。

对于开发者,可以通过 meta整个文档设置 Referer 策略。

<meta name="referrer" content="origin" />

当然也可以在 <a>、<area>、<img>、<iframe>、<script> 或者 <link> 元素上增加 referrerpolicy

<a href="http://example.com" referrerpolicy="origin">…</a>

3. 最佳实践

参考 web.dev 的 文章🔗建议明确设置增强隐私保护的策略,例如 strict-origin-when-cross-origin

最简单的方法如下:

客户端:

<meta name="referrer" content="strict-origin-when-cross-origin" />

服务端:

const helmet = require("helmet");
app.use(helmet.referrerPolicy({ policy: "strict-origin-when-cross-origin" }));

原因有四个。

  1. 兼容性。尽管通常这是个默认值,但不同浏览器或有不同的默认策略,明确设置可以提高兼容性和一致性。
  2. 安全。如果你的站点使用 HTTPS,那么网站的 URL 就不会泄露给非 HTTPS 的请求,因此免受中间人攻击。
  3. 增强隐私保护。对于跨域的访问,该 policy 仅共享来源,并不会共享全部网址。
  4. 内容共享。对于同站点的请求,该 policy 可以将全部信息共享。

4. 总结

由此可见,对于使用者而言,最好的策略往往是灰度的:不完全否定,有条件的信任。

对于产品的设计者,策略的设置则最好划分为几个梯度,允许开发者”渐进增强“。

(完)

参考

  1. HTTP Referer 教程 - 阮一峰的网络日志🔗
  2. HTTP 来源地址 - 维基百科,自由的百科全书🔗
  3. Referer and Referrer-Policy best practices | Articles | web.dev🔗
  4. 渐进增强 - 维基百科,自由的百科全书🔗
在 GitHub 上编辑本页面

最后更新于: 2024-11-20T09:44:17+08:00