Hero Image

引荐来源 (Referer) 和引荐来源政策 (Referrer-Policy) 最佳实践

引荐来源 (Referer) 和引荐来源政策 (Referrer-Policy) 最佳实践

设置引荐来源政策并在传入请求中使用引荐来源的最佳实践。

Updated
Appears in: Safe and secure

概述 #

  • 意外的跨域信息泄露是网络用户隐私的绊脚石。一个保护性引荐来源政策可以提供帮助。
  • 可以考虑设置 strict-origin-when-cross-origin 的引荐来源政策。该政策保留了引荐来源的大部分用途,同时降低了跨域泄露数据的风险。
  • 不要使用引荐来源来防范跨站请求伪造 (CSRF),而是用 CSRF 令牌和其他标头作为额外的一层安全保障。

在我们开始之前:

  • 如果您不确定"网站"和"域"之间的区别,请查看了解"同站"和"同域"
  • 由于规范中的原始拼写错误,Referer标头缺少一个 R。JavaScript 和 DOM 中的Referrer-Policy标头和referrer的拼写是正确的。

引荐来源和引荐来源政策 101 #

HTTP 请求可能包含可选的Referer标头,该标头指示发出请求的域或网页 URL。Referrer-Policy标头定义了在Referer标头中可用的数据。

在下方的示例中,Referer标头包含发出请求的site-one上页面的完整 URL。

包括一个引荐来源标头的 HTTP 请求。

Referer标头可能出现在不同类型的请求中:

  • 导航请求(当用户点击链接时)
  • 子资源请求(当浏览器请求页面需要的图像、iframe、脚本和其他资源时)

对于导航和 iframe,也可以通过 JavaScript 使用document.referrer访问这些数据。

Referer值可以提供非常有见解的信息。例如,分析服务可以使用该值来确定site-two.example上 50% 的访问者来自social-network.example

但是当包含路径和查询字符串的完整 URL 在Referer中被跨域发送时,就可能会有碍隐私并带来安全风险。请看下列这些网址:

带有路径的 URL 映射到不同的隐私和安全风险。

URL #1 到 #5 包含私人信息,有时甚至是识别信息或敏感信息。在不知不觉中跨域泄露这些信息可能会危及网络用户的隐私安全。

URL #6 是一个功能性 URL。不要让它落入目标用户之外的任何人手中。如果发生这种情况,恶意行为者可能会劫持该用户的帐号。

为了限制来自您网站的请求可以获取的引荐来源数据,您可以设置一个引荐来源政策。

有哪些可用的政策,它们之间有何不同? #

您可以从八种政策中选择一种。根据政策的选择, Referer标头(和document.referrer)中可用的数据可以是:

  • 无数据(不存在Referer标头)
  • 只有
  • 完整 URL:域、路径和查询字符串
引荐来源标头和 document.referrer 中可以包含的数据。

一些政策被设计为根据上下文的不同而采取不同行为:跨域或同域请求、安全性(无论请求目的地的安全性是否和域一样),或两者兼备。这对于限制跨域共享或限制向不太安全的域共享的信息量非常有用,同时也能够保持您自己的网站中引荐来源的丰富性。

以下概览显示了引荐来源政策对于引荐来源标头和document.referrer中可用 URL 数据的限制方式:

不同安全性和跨域上下文情况下的不同引荐来源政策及其行为。

MDN 提供了完整的政策和行为示例列表

注意事项:

  • 所有将方案(HTTPS 与 HTTP)考虑在内的政策(strict-originno-referrer-when-downgradestrict-origin-when-cross-origin)都会以相同的方式处理从一个 HTTP 域到另一个 HTTP 域的请求以及从一个 HTTPS 域到另一个 HTTPS 域的请求(即使 HTTP 的安全性更低)。这是因为对于这些政策来说,重要的是是否发生了安全降级,即请求是否可以将数据从一个加密域暴露给一个未加密域。 HTTP → HTTP 请求一直都是未加密的,因此不会出现降级。 相反,HTTPS → HTTP 请求会呈现降级。
  • 如果请求是同域的 ,这意味着方案(HTTPS 或 HTTP)相同,因此也就没有安全降级。

浏览器中的默认引荐来源政策 #

截至 2020 年 7 月

在未设置引荐来源政策的情况下将使用浏览器的默认政策。

浏览器默认Referrer-Policy/行为
Chrome计划在版本 85 中切换为strict-origin-when-cross-origin(以往是no-referrer-when-downgrade
Firefox
Edge
  • no-referrer-when-downgrade
  • 正在对strict-origin-when-cross-origin进行试验
Safaristrict-origin-when-cross-origin类似。请参阅阻止反跟踪进行跟踪了解详情。

设置您的引荐来源政策:最佳实践 #

Objective: 显式设置隐私增强政策,例如strict-origin-when-cross-origin(或更严格的政策)。

有多种方法可以为您的网站设置引荐来源政策:

您可以为不同的页面、请求或元素设置不同的政策。

HTTP 标头和元元素都是页面级的。确定一个元素的有效政策时的优先顺序是:

  1. 元素级政策
  2. 页面级政策
  3. 浏览器默认

示例:

index.html

<meta name="referrer" content="strict-origin-when-cross-origin" />
<img src="..." referrerpolicy="no-referrer-when-downgrade" />

图像请求将使用no-referrer-when-downgrade政策,而来自该页面的所有其他子资源请求将遵循strict-origin-when-cross-origin政策。

如何查看引荐来源政策? #

通过 securityheaders.com 可以方便地确定某个特定站点或页面正在使用的政策。

您还可以使用 Chrome、Edge 或 Firefox 的开发者工具查看用于特定请求的引荐来源政策。在撰写本文时,Safari 未显示Referrer-Policy标头,但会显示已发送的Referer

Chrome 开发者工具的网络面板截图,显示了引荐来源和引荐来源政策。
Chrome 开发者工具,网络面板中已选中一条请求。

您应该为您的网站设置哪种政策? #

概述:显式设置隐私增强政策,例如strict-origin-when-cross-origin(或更严格的政策)。

为什么要"显式"? #

在未设置引荐来源政策的情况下将使用浏览器的默认政策。事实上,网站通常会遵循浏览器的默认政策,但这并不理想,因为:

  • 取决于浏览器和模式(私密/无痕),其默认政策通常是no-referrer-when-downgradestrict-origin-when-cross-origin,或是更严格的政策。因此,您的网站在不同浏览器中的行为将无法预测。
  • 浏览器正在逐步采用更严格的默认政策,例如strict-origin-when-cross-origin,以及针对跨域请求的机制,例如引荐来源修剪。在浏览器的默认政策更改之前显式选择加入隐私增强政策可以让您掌握控制权,并帮助您按照您认为合适的方式运行测试。

为什么要用strict-origin-when-cross-origin(或更严格的政策)? #

您需要一个安全的、增强隐私且有用的政策,其中,"有用"的含义取决于您对引荐来源的需求:

  • 安全:如果您的网站使用 HTTPS(如果还未使用,请优先考虑迁移),则要杜绝网站的 URL 在非 HTTPS 请求中泄露。由于网络上的任何人都可以看到这些,这就会使您的用户面临中间人攻击。no-referrer-when-downgradestrict-origin-when-cross-originno-referrerstrict-origin政策解决了这个问题。
  • 隐私增强:对于跨域请求,no-referrer-when-downgrade会共享完整的 URL,因此并不能增强隐私。strict-origin-when-cross-originstrict-origin只共享域,而no-referrer完全不共享任何信息。您因此可以将strict-origin-when-cross-originstrict-originno-referrer作为隐私增强的选项。
  • 有用no-referrerstrict-origin永远不会共享完整的 URL,即使对于同域请求也不例外,所以如果您对此有需求, 那么strict-origin-when-cross-origin是更好的选择。

所有这些都表明**strict-origin-when-cross-origin**通常是一个明智的选择。

示例:设置一个strict-origin-when-cross-origin政策:

index.html

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

或服务端,例如在 Express 中:

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

如果strict-origin-when-cross-origin(或更严格的政策)不适用于您所有的用例怎么办? #

在这种情况下,采取渐进式方法:为您的网站设置一个保护性政策,例如strict-origin-when-cross-origin,如果有进一步需要,为特定请求或 HTML 元素设置一个更宽松的政策。

示例:元素级政策 #

index.html

<head>
<!-- document-level policy: strict-origin-when-cross-origin -->
<meta name="referrer" content="strict-origin-when-cross-origin" />
<head>
<body>
<!-- policy on this <a> element: no-referrer-when-downgrade -->
<a src="" href="" referrerpolicy="no-referrer-when-downgrade"></a>
<body></body>
</body>
</head>
</head>

请注意,Safari/WebKit 可能会限制跨站请求的document.referrerReferer标头。查看详情

示例:请求级政策 #

script.js

fetch(url, {referrerPolicy: 'no-referrer-when-downgrade'});

您还应该考虑什么? #

您的政策应该取决于您的网站和用例,而这又取决于您、您的团队和您的公司。如果某些 URL 包含识别或敏感数据,请设置一个保护性政策。

Warning: 对您来说或许不敏感的数据可能对您的用户来说是敏感数据,或者是他们根本不想或未预计到会不知不觉地跨域泄漏的数据。

使用传入请求中的引荐来源:最佳实践 #

如果您的网站功能使用传入请求的引荐来源 URL 怎么办? #

保护用户数据 #

Referer可能包含私密数据、个人数据或识别数据,因此请确保您对此类数据采用相应的对待方式。

请记住,您收到的Referer可能会发生改变 #

使用传入跨域请求中的引荐来源有一些限制:

  • 如果您无法控制请求发射器的执行情况,就不能对您收到的Referer标头(和document.referrer)做出假设。请求发射器可以随时决定切换到no-referrer政策,或者在更普遍的情况下切换到比之前更严格的政策,也就意味着您通过Referer获得的数据将比以前更少。
  • 默认情况下,浏览器会越来越多地使用strict-origin-when-cross-origin引荐来源政策。这意味着,如果发送这些请求的网站没有设置政策,您现在可能只会在传入跨域请求中收到域(而不是完整的引荐来源 URL)。
  • 浏览器可能会改变Referer的管理方式。例如,浏览器在将来可能会决定在跨域子资源请求中始终将引荐来源修剪到域,从而保护用户隐私。
  • Referer标头(和document.referrer)可能包含超出您需要的数据,例如当您只想知道请求是否为跨域时,却收到了完整的 URL。

Referer的替代方案 #

如果出现以下情况,您可能需要考虑替代方案:

  • 您网站的一项基本功能使用传入跨域请求中的引荐来源 URL;
  • 和/或如果您的网站不再接收其在跨域请求中所需的引荐来源 URL 部分。当请求发射器更改了政策或没有设置政策,并且浏览器的默认政策发生了变化(比如在 Chrome 85 中)时,就会发生这种情况。

要定义替代方案,请先分析您正在使用引荐来源的哪一部分。

如果您只需要域(https://site-one.example):

  • 如果您在对页面有顶级访问权限的脚本中使用引荐来源,那么window.location.origin是一种替代方案。
  • 在可用的情况下,如OriginSec-Fetch-Site这样的标头可以为您提供Origin或描述请求是否为跨域,这可能正是您所需要的。

如果您需要 URL 的其他元素(路径、查询参数……):

  • 请求参数或许适用于您的用例,而且可以为您省去解析引荐来源带来的工作。
  • 如果您在对页面有顶级访问权限的脚本中使用引荐来源,那么window.location.pathname是一种替代方案。仅提取 URL 的路径部分并将其作为参数传递,这样就不会传递 URL 参数中的任何潜在敏感信息。

如果您不能使用上述替代方案:

  • 检查您的系统是否可以更改为期望请求发射器(site-one.example)在某种配置下显式设置您需要的信息。优点:更明确、对site-one.example用户来说更保护隐私、更利于将来。缺点:可能会为您或您的系统用户带来更多的工作。
  • 检查发出请求的网站是否同意为每个元素或每个请求设置no-referrer-when-downgrade引荐来源政策。缺点:对site-one.example用户的隐私保护可能较弱、可能并非所有浏览器都支持。

跨站请求伪造 (CSRF) 保护 #

请注意,请求发射器始终可以通过设置一个no-referrer政策来决定不发送引荐来源(恶意行为者甚至可以伪造引荐来源)。

CSRF 令牌作为您的主要保护措施。要想获得额外保护,请使用SameSite,同时使用诸如Origin(可用于 POST 和 CORS 请求)和Sec-Fetch-Site(如果可用)这样的标头,而不是Referer

日志记录 #

请确保可能在Refer中的用户的个人数据或敏感数据得到保护。

如果您只使用域,请检查Origin标头是否可以作为替代方案。在调试方面,这可能会以更简单的方式为您提供所需信息,而无需解析引荐来源。

付款 #

付款服务提供商可能会依赖传入请求中的Referer标头来进行安全检查。

例如:

  • 用户单击online-shop.example/cart/checkout上的购买按钮。
  • online-shop.example重定向到payment-provider.example来管理交易。
  • payment-provider.example对照商家设置的Referer准许值列表检查该请求的Referer。如果在列表中未找到任何匹配条目,则payment-provider.example拒绝该请求。如果有匹配条目,则用户可以继续进行交易。

支付流程安全检查的最佳实践 #

概述:作为付款提供商,您可以将Referer作为针对朴素攻击的基本检查,但您一定需要有另一种更可靠的验证方法。

单独的Referer标头并不是一个可靠的检查依据:请求网站无论是否是合法商家,都可以设置一个no-referrer政策,这将使付款提供商无法获取Referer信息。但是,作为付款提供商,查看Referer可能会帮助您发现未设置no-referrer政策的朴素攻击者。因此,您可以使用Referer作为第一层基本检查。如果您这样做:

  • 不要期望Referer总是存在。如果Referer存在,那么只检查其至少会包括的那部分数据:域。在设置Refer准许值列表时,要确保不包括任何路径,只包括域。例如:online-shop.exampleRefer准许值应该是online-shop.example,而不是online-shop.example/cart/checkout。为什么?因为通过对根本没有Refer或者一个是请求网站的域的Refer值作出期望,您可以防止意外错误,因为您既没有对商家设置的**Referrer-Policy做出假设**,也没有对商家未设置政策情况下的浏览器行为做出假设。网站和浏览器都可以将传入请求中的Referer剥离出来,只保留域,或者根本不发送Referer
  • 如果Referer不存在,或者其存在并且您的基本Referer域检查成功:您可以继续使用其他更可靠的验证方法(见下文)。

有哪些更可靠的验证方法?

一种可靠的验证方法是让请求者将请求参数与唯一密钥一起散列。作为付款提供商,您接下来可以自己对相同的散列进行计算,并且仅在请求与您的计算匹配时才接受。

当一个没有引荐来源政策的 HTTP 商家网站重定向到一个 HTTPS 付款服务提供商时,Referer会发生什么?

在向 HTTPS 付款提供商发出的请求中不会看到Referer,因为当网站没有设置政策时,大多数浏览器默认使用strict-origin-when-cross-originno-referrer-when-downgrade。另请注意,Chrome 对新默认政策的更改不会改变此行为。

如果您的网站使用 HTTP,请迁移到 HTTPS

结论 #

一个保护性的引荐来源政策是为您的用户提供更多隐私保护的好方法。

如需了解不同用户保护技术的更多相关信息,请查看 web.dev 的安全和保障系列!

非常感谢所有审稿人的贡献和反馈:特别是 Kaustubha Govind、David Van Cleve、Mike West、Sam Dutton、Rowan Merewood、Jxck 和 Kayce Basques。

资源 #

Last updated: Improve article