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

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

熊崎裕树
熊崎博树

作为 Signed HTTP Exchanges (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 的路径,并对应于子资源。

锚标记

第一种比较简单,因为 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 工程师非常期待通过 webpackage-dev@chromium.org 收到您对于分发 SXG 的反馈。 您还可以加入规范讨论或向团队报告 bug。您的反馈将极大地帮助实现标准化过程,并帮助解决实现问题。 谢谢!