ChromeでHTTP/3サーバーをlocalhostに立てて自己証明書を信頼させてもHTTP/3通信できない + 解決策
#HTTP/3 #Chrome #QUIC
やりたいこと
ローカルにHTTP/3のサーバーを立てGoogle ChromeからHTTP/3でアクセスしたい。
起こったこと
HTTP/3をするにはhttpsをする必要があるため証明書を作る。だがそれを信頼させてもHTTP/3ではなくHTTP/1.1にフォールバックした。(HTTP/2にならないのは使ったライブラリの使い方の関係だと思う。)
解決策も書く。
環境
Mac
Chrome stable (90.0.4430.212)
chrome://flags/ の 「Experimental QUIC protocol」はDefaultのままで良い。
https://gyazo.com/950e54c3cc290ebf72251f53856650f6
HTTP/3サーバー
HTTP/3のサーバーは以下のquic-goを利用した。
code:go.mod
require github.com/lucas-clemente/quic-go v0.20.1
以下がサーバーのコード。
code:go
package main
import (
"fmt"
"github.com/lucas-clemente/quic-go/http3"
"net/http"
)
func main() {
fmt.Println("Running...")
http3.ListenAndServe(":8443", "fullchain1.pem", "privkey1.pem", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello, world\n"))
}))
}
localhostの自己署名SSL証明書
「localhostの自己署名SSL証明書をブラウザに信用させてHTTPSで通信する(Mac)」の方法を使って以下のようにlocalhostをChromeに信頼させる。赤くならず鍵のマークが正常になっていることがわかる。
https://gyazo.com/520b4c74b66a933b50dccd44c151a53c
だが、これだと以下のようにProtocolがhttp/1.1になる。
https://gyazo.com/c1bf55bf6e20aa69bb3757fb1bffe4ff
127.0.0.1にLet's Encrypt
この解決策として、
「127.0.0.1にLet' Encryptで証明書を発行してhttpsでのローカル開発と本番の差異を低減するための具体的な手順」の方法で自分の取得した127.0.0.1に向いているドメインに対して証明書を発行する。
この手法は「ローカル開発環境の https 化 | blog.jxck.io」を元にしている。
以下のようにちゃんと鍵がついている。localhost0.mlは127.0.0.1に向いているためローカルのサーバーにアクセスしている。
https://gyazo.com/cb9ce0d58b9b482e88daa2b433c29173
そして、以下のようにprotocolがh3-29になってHTTP/3で通信できていることがわかる。
https://gyazo.com/89b4915ac9774443f94a412e8e0880b1
これがChromeやChromiumの仕様や制約なのかはまだ不明。
hr.icon
少し泥臭いことを書くと、キャッシュみたいなのが効くのか通常のウインドウだとhttp/1.1のままなときに、プライベートブラウジングにすることでh3になったりする。あとリロードしたり再起動したりを何度かしている。そして何度かこういうことを繰り返してlocalhostの場合は一度もh3になることはなく、Let's Encryptを使った方法だとh3になることを確認して書いている。
何度か試して通常(not Incognito)のウインドウでもh3-29で通信した。画像はクリックで拡大する。
https://gyazo.com/5674e6e572b43da478dbe733adcf48a8
追記: 起動時にフラグをつけてHTTP/3通信をする
@bashik7氏の情報提供により、Chromeに起動時にフラグを渡すことで https://127.0.0.1:8443 で HTTP/3の通信が可能になった。以下のスレッドが元になっている。
まず証明書(以下の場合server.crt)を以下のコマンドでbase64の文字列にする。手元の証明書では出力が「tPefRj8ElIAExLRxhQD02miu1TJntrxz7eifF3+XgGo=」になった。
code:bash
openssl x509 -noout -pubkey -in server.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
元:
大元:
その後、以下のコマンドでChromeを立ち上げる。(この立ち上げ方の場合すでに開いていると適用されなかった記憶があるのでChromeを予め閉じておくと良いと思う。)
code:bash
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --origin-to-force-quic-on=127.0.0.1:8443 --ignore-certificate-errors-spki-list=tPefRj8ElIAExLRxhQD02miu1TJntrxz7eifF3+XgGo=
以下のようにh3-29で通信できていることがわかる。
https://gyazo.com/e30675132859958d53df546059643eb5
ただし現状でもlocalhostでHTTP/3通信はできていない。
Firefoxの場合はlocalhost可能
88.0.1では about:config で 「network.http.http3.enabled」を true にすれば HTTP/3通信できる。
https://gyazo.com/59640e723b5cd33ef4fc09d55bb173aa
以下のようにlocalhostでHTTP/3で通信できていることが分かる。
https://gyazo.com/7cc92f9784ea5618e323f3c137be622a
ただし「localhostの自己署名SSL証明書をブラウザに信用させてHTTPSで通信する(Mac)」の方法でもChromeと違ってFirefoxはシステムが信頼した証明書でも警告がでる。そのため鍵マークが黄色い。「赤い!」は文字のエンコードの警告なのでレスポンスを適切にすれば良い。