浏览器为CACHE提供过时的授权标头



我正在遇到我的客户端在向服务器发出无辜请求后登录。我控制了两端,经过大量调试后,我发现以下情况发生了:

  • 客户以正确的授权标头发送请求。
  • 服务器使用304 Not Modified响应没有任何授权标头。
  • 浏览器提供完整的响应,包括在其缓存中发现的过时授权标题
  • 从现在开始,客户使用过时的授权并被踢出。

据我所知,浏览器不得缓存任何包含授权的请求。尽管如此,

chrome://view-http-cache/http://localhost:10080/api/SearchHost

显示

HTTP/1.1 200 OK
Date: Thu, 23 Nov 2017 23:50:16 GMT
Vary: origin, accept-encoding, authorization, x-role
Cache-Control: must-revalidate
Server: 171123_073418-d8d7cb0 =
x-delay-seconds: 3
Authorization: Wl6pPirDLQqWqYv
Expires: Thu, 01 Jan 1970 00:00:00 GMT
ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
Content-Encoding: gzip
Content-Type: application/json;charset=utf-8
Content-Length: 255

有趣的服务器标头替换了一些内部信息替换Jetty Server标头(不应出于安全原因) - 忽略它。这就是卷曲所说的:

< HTTP/1.1 304 Not Modified
< Date: Thu, 23 Nov 2017 23:58:18 GMT
< Vary: origin, accept-encoding, authorization, x-role
< Cache-Control: must-revalidate
< Server: 171123_073418-d8d7cb0 =
< ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
< x-delay-seconds: 3
< Content-Encoding: gzip

这也发生在Firefox中,尽管我目前无法再现。 RFC继续进行,看来上面链接的答案并不精确:

,除非允许存储此类响应的缓存指令在响应

中存在

看起来响应是可以缓存的。很好,我确实希望 content 被缓存,但是我不希望从缓存提供授权标题。这可能吗?

我的问题的解释

我的服务器仅在响应登录请求时才用于发送Authorization标头。

我们的网站允许用户保持任意登录时间(我们没有敏感业务)。我们正在更改授权令牌的格式,因此我们不想强迫所有用户再次登录。因此,每当看到过时但有效的服务器时,我都使服务器发送更新的授权令牌。因此,现在任何响应都可能包含授权令牌,但其中大多数都不包含。

将仍然有效的响应与过时的授权令牌结合在一起的浏览器缓存出现。

作为解决方法,我在存在授权令牌时使服务器不发送etag。它有效,但我更喜欢一些更清洁的解决方案。

链接答案中的报价是误导性的,因为它省略了重要部分:缓存是共享的。这是正确的报价(RFC7234第3节):

缓存不得存储任何请求的响应,除非以下内容:...授权标题字段(请参阅[RFC7235]第4.2节)在请求中不会出现在请求中,如果缓存共享

RFC的部分基本上是一个摘要。这是完整的规则(RFC7234第3.2节),该规则本质上是同一件事:

a 共享的缓存不得使用授权标头字段([RFC7235]第4.2节)的请求的缓存响应,以满足任何后续请求,除非缓存响应中存在允许存储此类响应的指令。

浏览器缓存是共享缓存吗?RFC的引言部分说明了这一点:

相比之下,私有缓存专用于单个用户;通常,它们被用作用户代理的组件 。。

这意味着浏览器缓存是私有缓存。它不是共享的缓存,因此上述规则不适用,这意味着Chrome和Firefox都正确地完成了他们的工作。

现在是解决方案。

规范表明,有可能在没有授权标题的情况下重复使用的缓存响应。不幸的是,它还说该功能并未广泛实现。

因此,我能想到的最简单,最适合未来的解决方案是确保任何包含授权令牌的响应都不会缓存。例如,每当服务器看到过时但有效的授权令牌时,请将新有效的授权与Cache-Control: no-store一起发送以禁止缓存。

您也绝不能用授权标头发送Cache-Control: must-revalidate,因为must-revalidate指令实际上允许响应被缓存,包括通过共享caches将来会导致更多问题。

...除非允许存储此类响应的缓存指令存在于响应中。

在此规范中,以下高速缓存响应指令(第5.2.2节)具有这样的效果:必须重新定位,public和s-maxage。

我当前的解决方案是在每个响应中发送授权标头;当不需要授权时,使用-的占位符值。

占位符的价值显然毫无意义,客户知道它并愉快地忽略了它。

这个解决方案很难看,因为它为每个响应增加了20个字节,但这比偶尔必须像我的问题中提到的方法那样重新发出整个响应内容要好。此外,使用http/2可以免费。

最新更新