nginx を使用して Signed HTTP Exchange(SXG)を設定する方法

SXG 拡張機能を持つ TLS 証明書を生成する方法、SXG ファイルを生成するためのツールをインストールする方法、SXG ファイルを提供するように nginx を構成する方法。

Hiroki Kumazaki
Hiroki Kumazaki

Signed HTTP Exchange(SXG)は、ユーザーがコンテンツ クリエイターとコンテンツ配信者を簡単に区別できるようにする新しいウェブ技術です。このガイドでは、SXG を設定する方法について説明します。

クロスブラウザのサポート

SXG をサポートする Chromium ベースのブラウザには、Google Chrome、Samsung Internet、Microsoft Edge などがあります。最新の情報については、送信元署名済み HTTP エクスチェンジの「コンセンサスと標準化」セクションをご覧ください。

前提条件

ウェブサイトに SXG を実装するには、次の要件を満たす必要があります。

  • DNS エントリなど、ドメインを管理できる。
  • 証明書を取得します。SXG では、専用の証明書の発行が必要です。特に、TLS 鍵や証明書を再利用することはできません。
  • HTTPS 経由で SXG を生成して提供する HTTP サーバーがある。

前提条件

このガイドは、次の準備ができていることを前提としています。

  • OpenSSL 1.1.1 環境がある。このガイドは、amd64 ISA で Ubuntu 18.04 LTS を使用して作成されています。
  • sudo を実行して実行可能ファイルをインストールする機能。
  • HTTP サーバーとして nginx を使用します。
  • DigiCert を使用して、SXG 関連の拡張機能を含む証明書を生成しています。現在、これらの拡張機能をサポートしているプロバイダは DigiCert のみです。

また、この記事のサンプル コマンドはドメインが website.test であることを前提としています。website.test は実際のドメインに置き換える必要があります。

ステップ 1: SXG の証明書を取得する

SXG を生成するには、CanSignHttpExchanges 拡張を持つ TLS 証明書と特定の鍵タイプが必要です。DigiCert は、この拡張機能を含む証明書を提供しています。証明書の発行には CSR ファイルが必要であるため、次のコマンドを使用して CSR ファイルを生成します。

openssl ecparam -genkey -name prime256v1 -out mySxg.key
openssl req -new -key mySxg.key -nodes -out mySxg.csr -subj "/O=Test/C=US/CN=website.test"

次のような CSR ファイルが生成されます。

-----BEGIN CERTIFICATE REQUEST-----
MIHuMIGVAgEAMDMxDTALBgNVBAoMBFRlc3QxCzAJBgNVBAYTAlVTMRUwEwYDVQQD
DAx3ZWJzaXRlLnRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS7IVaeMvid
S5UO7BspzSe5eqT5Qk6X6dCggUiV/vyqQaFDjA/ALyTofgXpbCaksorPaDhdA+f9
APdHWkTbbdv1oAAwCgYIKoZIzj0EAwIDSAAwRQIhAIb7n7Kcc6Y6pU3vFr8SDNkB
kEadlVKNA24SVZ/hn3fjAiAS2tWXhYdJX6xjf2+DL/smB36MKbXg7VWy0K1tWmFi
Sg==
-----END CERTIFICATE REQUEST-----

次の点をご確認ください。

  • 有効期間は 90 日以内です。
  • [その他の証明書オプション] で [証明書に CanSignHttpExchanges 拡張機能を含める] チェックボックスがオンになっています。
[証明書に CanSignHttpExchanges 拡張機能を含める] チェックボックス。

証明書がこれらの条件を満たしていない場合、ブラウザと配信会社はセキュリティ上の理由から SXG を拒否します。このガイドでは、DigiCert から取得した証明書のファイル名が mySxg.pem であることを前提としています。

ステップ 2: libsxg をインストールする

SXG 形式は複雑で、ツールを使用せずに生成するのは困難です。SXG は、次のいずれかの方法で生成できます。

このガイドでは libsxg を使用します。

オプション 1: Debian パッケージから libsxg をインストールする

OpenSSL(libssl-dev)のバージョンが一致していれば、通常の Debian の方法でパッケージをインストールできます。

sudo apt install -y libssl-dev
wget https://github.com/google/libsxg/releases/download/v0.2/libsxg0_0.2-1_amd64.deb
wget https://github.com/google/libsxg/releases/download/v0.2/libsxg-dev_0.2-1_amd64.deb
sudo dpkg -i libsxg0_0.2-1_amd64.deb
sudo dpkg -i libsxg-dev_0.2-1_amd64.deb

オプション 2: libsxg を手動でビルドする

.deb ファイルと互換性のある環境を使用していない場合は、libsxg を自分でビルドできます。前提条件として、gitcmakeopensslgcc をインストールする必要があります。

git clone https://github.com/google/libsxg
mkdir libsxg/build
cd libsxg/build
cmake .. -DRUN_TEST=false -DCMAKE_BUILD_TYPE=Release
make
sudo make install

ステップ 3: nginx プラグインをインストールする

nginx プラグインを使用すると、サービング前に SXG を静的に生成するのではなく、動的に生成できます。

オプション 1: Debian パッケージからプラグインをインストールする

nginx の SXG モジュールは GitHub で配布されています。Debian ベースのシステムでは、バイナリ パッケージとしてインストールできます。

sudo apt install -y nginx=1.15.9-0
wget https://github.com/google/nginx-sxg-module/releases/download/v0.1/libnginx-mod-http-sxg-filter_1.15.9-0ubuntu1.1_amd64.deb
sudo dpkg -i libnginx-mod-http-sxg-filter_1.15.9-0ubuntu1.1_amd64.deb

オプション 2: プラグインを手動でビルドする

nginx モジュールをビルドするには、nginx ソースコードが必要です。次のコマンドを使用して、tarball を取得し、SXG 動的モジュールとともにビルドできます。

git clone https://github.com/google/nginx-sxg-module
wget https://nginx.org/download/nginx-1.17.5.tar.gz
tar xvf nginx-1.17.5.tar.gz
cd nginx-1.17.5
./configure --prefix=/opt/nginx --add-dynamic-module=../nginx-sxg-module --without-http_rewrite_module --with-http_ssl_module
make
sudo make install

nginx 構成は柔軟性に優れています。システムの任意の場所に nginx をインストールし、それぞれのパスとして module/config/log/pidfile を指定します。このガイドでは、/opt/nginx にインストールすることを前提としています。

ステップ 4: SXG で動作するように nginx プラグインを構成する

オプション 1: Debian からインストールされた nginx モジュールを構成する

前述のステップ 3、オプション 1 を使用した場合は、次の手順を行います。

SXG コンテンツを配信するには HTTPS が必要です。SSL/TLS 証明書は、DigiCert、Let's Encrypt などのサービスから取得できます。SXG 証明書を SSL に使用したり、その逆を行ったりすることはできません。そのため、2 つの証明書が必要になります。SSL 鍵と証明書のペアを /path/to/ssl/ に、SXG の鍵と証明書のペアを /path/to/sxg/ に配置した場合、/etc/nginx/nginx.conf の構成ファイルは次のようになります。

user www-data;
include /etc/nginx/modules-enabled/*.conf;

events {
     worker_connections 768;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    add_header  X-Content-Type-Options nosniff;

    server {
        listen 443 ssl;
        ssl_certificate     /path/to/ssl/fullchain.pem;
        ssl_certificate_key /path/to/ssl/privkey.pem;
        server_name  website.test;

        sxg on;
        sxg_certificate     /path/to/sxg/mySxg.pem;
        sxg_certificate_key /path/to/sxg/mySxg.key;
        sxg_cert_url        https://website.test/certs/cert.cbor;
        sxg_validity_url    https://website.test/validity/resource.msg;
        sxg_cert_path       /certs/cert.cbor;

        root /var/www/html;
    }
}
  • sxg_cert_url は、証明書チェーンを検出するため、ブラウザが SXG を適切に読み込むために不可欠です。証明書チェーンには、証明書と OCSP スタッキング情報が cbor 形式で含まれています。cert.cbor ファイルを同じオリジンから提供する必要はありません。HTTPS をサポートしている限り、任意の CDN またはその他の静的ファイル サービング サービス経由で提供できます。
  • sxg_validitiy_url は SXG-signature-header 関連情報を提供する予定です。前回の SXG 以降にページが変更されていない場合、技術的には SXG ファイル全体をダウンロードする必要はありません。そのため、署名ヘッダー情報を更新するだけでネットワーク トラフィックを削減できると予想されます。詳細はまだ実装されていません。

nginx を起動すると、SXG を提供する準備が整います。

sudo systemctl start nginx.service
curl -H"Accept: application/signed-exchange;v=b3" https://website.test/ > index.html.sxg
cat index.html.sxg
sxg1-b3...https://website.test/...(omit)

オプション 2: ソースからビルドされた nginx モジュールを構成する

以前にステップ 3、オプション 2 を使用した場合は、次の手順を行います。

/opt/nginx にインストールされている nginx システムを、次の例のように構成します。

load_module "/opt/nginx/modules/ngx_http_sxg_filter_module.so";

events {
    worker_connections 768;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    add_header X-Content-Type-Options nosniff;

    server {
        listen 443 ssl;
        ssl_certificate     /path/to/ssl/fullchain.pem;
        ssl_certificate_key /path/to/ssl/privkey.pem;
        server_name  example.com;

        sxg on;
        sxg_certificate     /path/to/sxg/mySxg.pem;
        sxg_certificate_key /path/to/sxg/mySxg.key;
        sxg_cert_url        https://website.test/certs/cert.cbor;
        sxg_validity_url    https://website.test/validity/resource.msg;
        sxg_cert_path       /certs/cert.cbor;

        root /opt/nginx/html;
    }
}

次に、nginx を開始します。SXG をゲットできるようになりました!

cd /opt/nginx/sbin
sudo ./nginx
curl -H "Accept: application/signed-exchange;v=b3" https://website.test/ > index.html.sxg
less index.html.sxg
sxg1-b3...https://website.test/...(omit)

ステップ 5: アプリケーション バックエンドを提供する

上記の例では、nginx はルート ディレクトリの静的ファイルを提供しますが、nginx がフロント HTTP(S) サーバーとして機能している限り、アプリケーションのアップストリーム ディレクティブを使用して、任意のウェブ アプリケーション バックエンド(Ruby on Rails、Django、Express など)の SXG を作成できます。

upstream app {
    server 127.0.0.1:8080;
}

server {
    location / {
        proxy_pass http://app;
    }
}

ステップ 6: テスト

dump-signedexchange ツールを使用して、提供される SXG が正しいことをテストし、エラーが報告されていないことを確認して、ヘッダーと本文が想定どおりであることを確認します。

go get -u github.com/WICG/webpackage/go/signedexchange/cmd/dump-signedexchange
export PATH=$PATH:~/go/bin
dump-signedexchange -verify -uri https://website.test/ | less

フィードバックを送信

SXG に取り組んでいる Chromium エンジニアは、webpackage-dev@chromium.org で皆様からのフィードバックをお待ちしております。仕様に関するディスカッションに参加したり、チームにバグを報告したりすることもできます。いただいたフィードバックは、標準化プロセスの推進と実装に関する問題の解決に役立てさせていただきます。 ありがとうございました