为什么 Chrome 不允许通过扩展修改这些标头?

信息安全 铬合金 标题
2021-08-27 14:55:37

Chrome WebRequests API提到特定的请求标头对onBeforeSendHeaders事件不可用,这意味着扩展无法读取和/或修改这些标头。这是文档的摘录:

当前未向onBeforeSendHeaders事件提供以下标题。此列表不保证完整或稳定。

  • 授权
  • 缓存控制
  • 联系
  • 内容长度
  • 主持人
  • If-Modified-Since
  • 如果无匹配
  • 如果范围
  • 部分数据
  • 编译指示
  • 代理授权
  • 代理连接
  • 传输编码

是否有安全理由禁止扩展读取或写入这些?如果一个扩展可以读/写这些值,它怎么可能是恶意的?


澄清:我知道为什么对其中一些进行读取访问是一个坏主意,最突出的是任何带有身份验证数据的标头。Host但是,其他标题,例如ConnectionContent-Length对我来说完全是个谜。

此外,我不清楚为什么这些标头中的一些完全无法被扩展访问,而不是允许设置值或附加值,即使未授予读取访问权限。

3个回答

我同意 OP 的观点,即在安全性方面允许更广泛的数据时,仅阻止对这些标头的访问是没有意义的。没有它们,恶意插件可以造成如此多的破坏。

从 API 文档的阅读来看,听起来不允许访问这些标头的原因不一定是出于安全考虑,而更多是因为当前 Chrome 引擎的工作方式。听起来 Chrome 的请求处理管道即使在 API 修改完成后仍在继续。Chrome 如何管理网络请求和缓存的一方面。由于请求管道中的那些下游组件可以做出不同的决定并更改这些标头,我猜这就是为什么它甚至不让您阅读它们 b/c 它不能保证它们会保持不变。

这是基于他们在chrome.WebRequest 文档中的解释

(*) 请注意,Web 请求 API 将网络堆栈的抽象呈现给扩展。在内部,一个 URL 请求可以拆分为多个 HTTP 请求(例如从一个大文件中获取单个字节范围),或者可以由网络堆栈处理而不与网络通信。因此,API 不提供发送到网络的最终 HTTP 标头。例如,所有与缓存相关的标头对扩展都是不可见的。

以下标头当前未提供给 onBeforeSendHeaders 事件。此列表不保证完整或稳定。

... OP 质疑的标题列表 ....

如果您在页面中进一步阅读,它会更多地解释缓存问题。在我看来,Chrome 不喜欢公开请求管道的某些部分(特别是影响网络通信决策的事物,包括缓存),这可能是出于一些好的技术原因(可能需要进行重大的设计更改)。

由于这些隐藏的管道部分可能会在您的插件修改完成后做出不同的决定,Chrome 不允许您阅读它们,因为下游管道组件可能仍会更改它们。看看它如何谈论 API 不可见的“内存缓存”。这听起来像是 Chrome 的设计挑战(或者不让插件影响其网络性能的偏好)。所以我会得出结论,这不一定是因为安全。

缓存:Chrome 使用两个缓存——一个磁盘缓存和一个非常快的内存缓存。内存缓存的生命周期与渲染进程的生命周期相关联,渲染进程的生命周期大致对应于一个选项卡。 从内存缓存响应的请求对 Web 请求 API 是不可见的。如果请求处理程序更改其行为(例如,根据哪些请求被阻止的行为),则简单的页面刷新可能不会考虑此更改的行为。要确保行为更改通过,请调用 handlerBehaviorChanged() 以刷新内存缓存。但不要经常这样做;刷新缓存是一项非常昂贵的操作。在注册或注销事件侦听器后,您无需调用 handlerBehaviorChanged()。

是否有安全理由禁止扩展读取或写入这些?

是的,标题以某种或其他形式用作保护手段。因此,天生保护这些标头免受修补继承了优先级。

如果一个扩展可以读/写这些值,它怎么可能是恶意的?我不清楚为什么这些标头中的一些是扩展完全无法访问的,而不是允许设置一个值或附加一个值,即使没有授予读取访问权限。

我如何尝试得出以下答案:我已经详细说明了扩展以提供使用上下文,然后积累足够的信息来定义与标头相关的风险和攻击向量并列出它们。如果您发现任何信息已过时或不正确,请随时编辑答案或启发我。

授权 HTTP Authorization 请求标头包含向服务器验证用户代理的凭据,通常但不一定在服务器响应 401 Unauthorized 状态和 WWW-Authenticate 标头之后。

攻击者可以将授权值写入其会话的授权值,以使受害者为攻击者的签出付费。读取此值允许攻击者窃取身份并冒充用户或代表他执行操作。

Cache-Control Cache-Control HTTP 标头包含用于在请求和响应中进行缓存的指令(指令)。请求中的给定指令并不意味着响应中应该有相同的指令。

如果可以设置此值,则攻击者可以允许将敏感信息的缓存存储在浏览器上,并在以后的时间点访问它。

Connection Connection 通用标头控制当前事务完成后网络连接是否保持打开状态。如果发送的值是 keep-alive,则连接是持久的并且不会关闭,从而允许完成对同一服务器的后续请求。

持久连接也有缺点;即使在空闲时它们也会消耗服务器资源,并且在负载较重的情况下,也可以进行 DoS 攻击。

Content-Length Content-Length 实体标头指示发送给接收者的实体主体的大小(以字节为单位)。

Content-Length 标头用于 HTTP 1.1,以便接收方知道当前响应*何时完成,因此可以将连接重用于另一个请求。同样,如果连接保持很长时间,它会消耗资源并可能导致 DoS。

Host Host 请求头指定了请求被发送到的服务器的主机和端口号。

如果动态更改主机标头,则整个请求将落在攻击者托管的恶意服务器上,最终共享 cookie 和其他敏感数据。

If-Modified-Since If-Modified-Since 请求 HTTP 标头使请求有条件:服务器将返回请求的资源,状态为 200,仅当它在给定日期之后最后一次修改时。

攻击者可以针对特定主机/主机的 GET 和 HEAD 请求并更改此特定标头以实现 DoS。

If-None-Match If-None-Match HTTP 请求标头使请求有条件。对于 GET 和 HEAD 方法,服务器将发送回请求的资源,状态为 200,前提是它没有与给定资源匹配的 ETag。

与 If-Modified-Since 相同,攻击者可以针对特定主机/主机的 GET 和 HEAD 请求并更改此特定标头以实现 DoS。

If-Range If-Range HTTP 请求标头使范围请求成为有条件的:如果满足条件,将发出范围请求,并且服务器发回带有适当正文的 206 Partial Content 答案。

与 If-Modified-Since 类似,攻击者可以针对特定主机/主机的请求并更改此特定标头以实现 DoS 攻击。

Partial-Data Range HTTP 请求标头指示服务器应返回的文档部分。如果服务器发回范围,它使用 206 Partial Content 作为响应。

由于多部分/字节范围有效负载部分之间的典型开销约为 80 字节,具体取决于所选表示的媒体类型和所选边界参数长度,传输许多小的不相交部分的效率可能低于传输整个选定的表示。无法处理多部分/字节范围响应的客户端不得生成请求多个范围的请求。当生成多部分响应负载时,服务器应该按照相应的字节范围规范出现在接收到的 Range 头字段中的相同顺序发送部分,不包括那些被认为不合理或合并到其他范围的范围。

Pragma它用于向后兼容 HTTP/1.0 缓存,其中 Cache-Control HTTP/1.1 标头尚不存在。当请求中也存在并理解 Cache-Control 标头字段时,将忽略 Pragma。

Pragma: no-cache强制缓存在释放缓存副本之前将请求提交给源服务器进行验证。如果更改成功,则可以在浏览器中执行注入,尤其是旧版本。

Proxy-Authorization HTTP Proxy-Authorization 请求标头包含向代理服务器验证用户代理的凭据,通常在服务器响应 407 Proxy Authentication Required 状态和 Proxy-Authenticate 标头之后。

类似于授权标头。攻击者可能会读取此标头的值并将其用于恶意目的。

Proxy-Connection Proxy-Connection 指定在请求发送后连接是否保持打开。如果该值指示连接可以保持打开状态,则 HTTP 1.1 代理将接受可以针对服务器 URI 执行的后续请求。

与 Connection 头类似,持久连接也有缺点;即使在空闲时它们也会消耗服务器资源,并且在负载较重的情况下,也可以进行 DoS 攻击。

Transfer-Encoding Transfer-Encoding 标头指定用于将有效负载主体安全地传输给用户的编码形式。

与 Partial-Data 头的讨论类似,Transfer-Encoding 是逐跳头,应用于两个节点之间的消息,而不是资源本身。

Transfer-Encoding: chunked
Transfer-Encoding: compress
Transfer-Encoding: deflate
Transfer-Encoding: gzip
Transfer-Encoding: identity

例如,当向客户端发送大量数据并且在请求完全处理之前可能不知道响应的总大小时,分块编码很有用。如果更改此标头的值,可能会导致解析类似于 Partial-Data 标头的数据出现问题。

现在,如果浏览器的扩展被攻击者利用。根据服务器/应用程序/浏览器的漏洞或所有它们的混合和匹配,它有可能用于更改值或读取这些标头的值。攻击者也有可能使用代理的隐藏功能进行扩展,以通过浏览器拦截或读取流量。此处使用示例场景和相关代码描述了一种用于拦截/读取流量的 JavaScript 实现:https ://medium.com/dailyjs/how-to-use-javascript-proxies-for-fun-and-profit-365579d4a9f8

学分/参考:

我认为浏览器扩展具有与它们相关的风险,这些风险记录在其他地方。据我了解,这个问题专门针对浏览器扩展可能使用的这个 API。如果我正确理解了这个问题,并不是他们拒绝访问这些标头,而是为什么. 考虑到这些,让我们跳过一般的浏览器扩展安全性和一般的请求标头安全性。让我们关注意图/要求。

API的意图存在于问题链接的文档中,并且可以被视为要求:

使用 chrome.webRequest API 观察和分析流量并拦截、阻止或修改正在进行的请求。

因此,API 的要求有两个方面:

  1. 观察和分析流量
  2. 拦截、阻止或修改请求

这是一个有隐私意识的人间接感谢的有效意图,因为它为广告拦截器和其他以隐私为重点的浏览器扩展提供了动力。

这不是为什么特定标头无法访问的问题。相反,这是一个最小特权的问题。API 设计者不得不回答这个问题,“在 RFC 中所有可能的标头中,哪些是满足要求所必需的,哪些不是?”。

API 设计者可以在列表中没有任何标题的情况下满足要求。另外,我认为它解释了为什么文档指出该列表既不保证也不稳定。这表明大多数标题通常不需要满足意图/要求。