如何使用 nginx 分发 Signed HTTP Exchange (SXG)

如何使用 nginx 获取和传送 SXG 文件,以及子资源预提取带来的挑战。

Hiroki Kumazaki
Hiroki Kumazaki

作为 Signed HTTP Exchange (SXG) 分销商,您可以代表原始内容创作者提交 SXG 文件。支持 SXG 的网络浏览器会显示此类 SXG 文件,就像它们是由原始内容创作者提供的文件一样。这样,您就可以在不侵犯隐私权的情况下实现跨网站预加载。本指南将向您介绍如何正确分发 SXG。

跨浏览器支持

Chrome 是目前唯一支持 SXG 的浏览器。参阅共识和如需了解最新信息,请参阅源签名 HTTP 交换的“标准化”部分。

获取 SXG 文件

Accept 请求标头中指定您希望服务器随请求一起返回 SXG 文件:

Accept: application/signed-exchange;v=b3,*/*;q=0.8

本指南假定您将 SXG 文件放在 /var/www/sxg 中。

提供简单的 SXG 文件

请附加以下标头以分发单个 SXG 文件:

Content-Type: application/signed-exchange;v=v3
X-Content-Type-Options: nosniff

配置 nginx

http {
    ...
    types {
        application/signed-exchange;v=b3  sxg;
    }
    add_header X-Content-Type-Options nosniff;

    location / {
        more_set_headers "Content-Type: application/signed-exchange;v=b3";
        alias /var/www/sxg/;
        try_files $uri.sxg $uri =404;
        autoindex off;
    }
    ...

将新配置加载到 nginx 中:

sudo systemctl restart nginx.service

nginx”将开始投放 SXG 文件。 当 Chrome 访问您的服务器时,地址栏中会显示原始内容发布者的地址!

预提取子资源

大多数网页都由多个子资源组成,例如 CSS、JavaScript、字体和图片。 如果没有内容创作者的私钥,则无法更改 SXG 的内容。 这会导致浏览器尝试解析子资源时出现问题。

例如,假设 https://website.test/index.html 中的 index.html.sxg 包含指向 https://website.test/app.js 的链接。当用户的浏览器收到来自 https://distributor.test/example.com/index.html.sxg 的 SXG 文件时,会找到指向 https://website.test/app.js 的链接。 浏览器可以在实际访问时直接提取 https://website.test/app.js,但为了保护隐私,不应在预加载阶段执行此操作。 如果在预加载阶段提取了资源,内容创作者 (website.test) 或许能够检测到哪个内容分发方 (distributor.test) 正在请求该资源。

distributor.test/index.html.sxg 中指向 app.js 的链接指向 website.test/app.js。

如果分销商希望通过自己的服务提供 app.js.sxg,并尝试将 https://website.test/app.js 修改为分销商的该子资源版本(例如 https://distributor.test/website.test/app.js.sxg),则会导致签名不匹配并使 SXG 无效。

尝试将 distributor.test/index.html.sxg 中的 app.js 引用链接到 distributor.test/app.js 会导致签名不匹配。

为了解决这个问题,Chrome 现在提供了一项实验性的 SXG 子资源预提取功能。 您可以在以下网址启用它:about://flags/#enable-sxg-subresource-prefetching。 如需使用子资源预提取功能,必须满足以下条件:

  • 发布商必须在 SXG 中嵌入响应标头条目,例如:link: <https://website.test/app.js>;rel="preload";as="script",<https://website.test/app.js>;rel="allowed-alt-sxg";header-integrity="sha256-h6GuCtTXe2nITIHHpJM+xCxcKrYDpOFcIXjihE4asxk="。这会指定可被 SXG 的特定完整性哈希替换的子资源。
  • 分销商在传送 SXG 时必须附加响应标头,例如:link: <https://distributor.test/website.test/app.js.sxg>;rel="alternate";type="application/signed-exchange;v=b3";anchor="https://website.test/app.js"。此参数指定 app.js 的路径,并对应于子资源。

anchor

第一种方法比较简单,因为 nginx-sxg-module 可以计算完整性哈希值,并将其嵌入上游响应的链接标头中。但第二种方法比较困难,因为内容分发者必须知道 SXG 中的指定子资源。

如果除了 https://website.test/app.js 之外没有子资源,则只需在 nginx 配置中附加以下内容:

add_header link <https://distributor.test/website.test/app.js.sxg>;rel="alter...

但这种情况很少见,因为典型的网站都包含大量子资源。此外,分销商在提供 SXG 文件时必须附加正确的锚链接标头。目前,没有什么简单的方法可以解决此问题,因此请密切关注最新动态!

发送反馈

Chromium 工程师热切希望收到您对分发 SXG 的反馈,地址为 webpackage-dev@chromium.org。 您还可以参与规范讨论,或向团队报告 bug。 您的反馈将非常有助于完成标准化流程,并有助于解决实施问题。 谢谢!