NginxとOpenSSL 1.1.1でTLS 1.3対応にした(docker, Alpine Linux)

孤独のIT

このサイトで、TLS 1.3を有効にしてみた。色々と知見が得られたのでまとめておきます。

TLS 1.3 にするメリット

よく知らなかったので適当に調べてみると、ふつうの人にも嬉しい点は以下のところ。

  • セキュリティが強化される。
  • ハンドシェイクが速くなる(ので、最初のアクセスが速い)。
  • 0-RTT が有効だとハンドシェイク処理が不要になり、速くなる(でもセキュリティ問題が新たに発生するので、今回は設定してない)。

速くなってセキュリティ強化もされるので、やらない手はないですね。ブラウザが非対応ならTLS 1.2で接続できるように設定すればいいので問題なしです。

ところで、TLS 1.2もRFC正式化がもう10年以上前(2008年8月)ってマジすか。新しいと思ってたのに…

TLS 1.3 対応ブラウザ

一般的に使われているブラウザとしては、以下の感じらしい。まだまだですね。

  • Chrome 70以降
  • Firefox 63以降
  • Edge 未対応 (開発中)
  • Safari 未対応 (開発中)

IE? 知らない子ですね…

TLS 1.3 対応するにはOpenSSL 1.1.1以降が必要

Nginx + OpenSSLの場合、OpenSSL 1.1.1以降ならTLS 1.3に対応しているらしい。OpenSSL 1.1.1は2018年9月にリリースされたようで、主要なLinuxディストリビューションの安定版リリースにはまだ含まれていない模様。

Alpine Linux 3.9.0以降ならOpenSSL 1.1.1

このサイトでは元々Dockerを利用して運用しているので、Nginxを動かすOSは選び放題です。

そこでAlpine Linuxですよ、と思って docker run してみると、見事にOpenSSL 1.1.1でした。素晴らしい。Nginx公式dockerイメージにはOSがalpineベースのものもあるので、これを使うことにしました。執筆時点では nginx/1.15.11

ところで、Alpine Linuxって3.9.0から(過去に切り替えた)LibreSSLからOpenSSLに切り替えてるんですね。軽くググるとABI互換性問題が理由なんでしょうか。なかなか難しい。

ちなみに、今まで https-portal を使ってたので、移行がちょっとめんどかった。やはり、なるべくスタンダードなものを使うべきですね。

NginxのTLS 1.3設定と関連の設定

この記事を書いている段階では、だいたい以下のようになっています。

server {
    listen 443 ssl http2;
    server_name 2502.net;

    ssl_certificate /etc/letsencrypt/live/2502.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/2502.net/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/2502.net/fullchain.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/private/dhparam.pem;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
}

この状態で、Qualys SSL Labsのテストをしてみると A+ をいただけます。やったぜ。 → 2502.netのテスト結果

SSL Labs の結果

ssl_protocols

Nginxでは ssl_protocolsTLSv1.3 を入れると、TLS 1.3が有効になります。

TLS 1.0と1.1はそろそろ切ってもいいかなーと思いつつ、まだ残しています。SSL Labsの結果で、各OS・ブラウザのシミュレーションが見られて便利なのですが、Android 4.3以下やIE10以下等がTLS 1.0で接続する(TLS 1.1以上に対応していない)ようです。まだ結構使ってる人いそうですよね…(セキュリティ的によろしくないので、早めに更新していただきたいです)

ssl_ciphers

ssl_ciphersについては、現代ではデフォルトでいいかなと思って設定していません。デフォルトを決めるエンジニアの良心を信じます(他力本願)。SSLv3が生きていた時代は、設定しないとヤバそうでしたが。

私のように、TLS方面の最新情報を常に追っているわけでもない怠惰なエンジニアの場合は、こういう細かい設定は下手に変更しないほうが適切な設定になる可能性が高いと考えました。このような場合は、最新のソフトウェアを使うのが重要です。

OCSP Stapling

このあたりの設定で、OCSP Staplingが有効になります。

ssl_trusted_certificate /etc/letsencrypt/live/2502.net/fullchain.pem;
ssl_dhparam /etc/ssl/private/dhparam.pem;
ssl_stapling on;
ssl_stapling_verify on;

OCSP Staplingは、サーバー証明書が失効していないか確認するためにクライアントが行わなければならない手順(OCSP)をサーバーが代わりに行ってキャッシュしておくことにより、無駄を減らしてHTTPS通信の開始を高速化する技術です。

速いのはみんなにうれしいですね。

ssl_session_timeout, ssl_session_cache

Mozilla SSL Configuration Generatorの値を使いました。

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;

HSTS: HTTP Strict Transport Security

「このサイトは常時HTTPSで通信しまっせ」という意思を示すHTTPヘッダ設定です。

add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';

常時HTTPSはGoogleなどが推進しており、SEO的にも多少は意味があるようです。HSTSを設定しても悪い効果はないでしょう。

HSTS Preload も設定してみました。こちらは、ブラウザが持っている「このドメインはHSTS対応サイト」のリストに加えてもらうことで、初回のアクセス時から生HTTP通信を避けてHTTPSで接続し、セキュリティ強化と高速化を得ることができる技術です。

先日、 https://hstspreload.org/ で登録してみましたが、いつ有効になるんでしょうか。まあ、そんなに急がないので気長に待ちます。

2019-04-22追記: 確認してみたら、 “Status: 2502.net is currently preloaded.” となっていました。やったぜ。毎日確認してなかったので正確なところはわかりませんが、一週間以内くらいで有効になるようですね。

TLS 1.3 接続テスト

Qualys SSL Labs で接続テスト

上にも書きましたが、便利なテストスイートサイトです。ここで高評価を得られれば、TLSに関してはそんなにマズい状態にはならないはず。 → 2502.netのテスト結果

Google Chrome で接続テスト

Ctrl + Shift + I でデベロッパーツールを開いて Security タブを見ると、TLSのバージョンいくつで接続してるかを確認することができます。

Chrome 73 で確認したところ

ちゃんと “using TLS 1.3” と表示されていますね。

openssl s_client で接続テスト

OpenSSL 1.1.1の環境がなかったので、dockerでnginx:alpineイメージで実行。OpenSSLが入ってないので、 apk add openssl でインストールしてから接続テスト。apkコマンド、一瞬で終わるので好き。

$ docker run --rm -it nginx:alpine /bin/sh                                                                                                                                                                                             
/ # apk add openssl
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
(1/1) Installing openssl (1.1.1b-r1)
Executing busybox-1.29.3-r10.trigger
OK: 16 MiB in 30 packages
/ # openssl s_client -connect 2502.net -port 443 -tls1_3
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = 2502.net
verify return:1
---
Certificate chain
 0 s:CN = 2502.net
   i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
(snip)
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
(snip)

無事にTLS 1.3で接続できているようです。

参考リンク

あとがき

いじってる途中、Alpine Linuxに搭載されている busybox の /bin/sh が進化してて、ファイル名やディレクトリ名を TAB で補完できたので感動した。いつからだろ。

タイトルとURLをコピーしました