Qualys SSL Server Test: https://www.ssllabs.com/ssltest/
追記
- 2018-12-05 OpenSSL v1.1.1 および TLS v1.3 用の対応を追記。
- 2019-04-04
TLS_AES_128_GCM_SHA256
無効化について追記。 - 2019-08-31 CBC 暗号スイートの無効化について追記。
- 2022-06-08 nginx における TLS v1.3 の暗号スイートの設定方法を追記。
注意
A+ 評価はいいとしても、満点を取ろうとすると、対応ブラウザが少なくなったり、サーバ負荷が高くなったりします。
実運用では A もしくは A+ 評価を目指すまでに留め、満点は趣味でやってみるくらいでいいかと思います。
証明書取得時の注意
もし満点を達成しようとするのであれば、証明書の鍵長を 4096bit 以上にする必要があります。
鍵長が 4096bit 以上でなければ、 Key Exchange が 100 になりません。
参考: Let’s EncryptでSSL/TLS証明書のRSA鍵長を4096ビットにする方法 | Webセキュリティの小部屋
SSL 関係の設定 (アルファベット順)
# HSTS を有効にする。
# これを有効にすると、クライアントは、初回接続以降は「必ず」 https で接続してくるようになる。
# 有効にしないと A が評価の上限になり、有効にすることで A+ 評価になる。
# 「必ず」 https 接続になっていいかどうかはサービスによるので、設定には注意すること。
add_header Strict-Transport-Security 'max-age=31536000;' always;
# HSTS Preload に登録する場合は、サブドメインも全て https に対応させ、
# ヘッダに includeSubDomains と preload も含めるようにする。
# @see https://hstspreload.org/
#add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;
# OCSP Stapling に対応するため、ネームサーバを設定する必要がある。
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# 証明書に対応する公開鍵を指定。
# 自分自身の証明書~中間証明書~ルート証明書の一つ前 までの順に結合したファイルを指定する。
# COMODO の PositiveSSL ならば、送付される証明書に含まれる
# {your domain}.crt
# COMODORSADomainValidationSecureServerCA.crt
# COMODORSAAddTrustCA.crt
# の 3 つを、この順に結合する。
# 例)
# cat {your domain}.crt \
# COMODORSADomainValidationSecureServerCA.crt \
# COMODORSAAddTrustCA.crt \
# > server.crt
#
# Let's Encrypt なら fullchain.pem を指定する。
ssl_certificate /path/to/fullchain.pem;
# 証明書に対応する秘密鍵を指定。
ssl_certificate_key /path/to/privkey.pem;
# RSA は WEAK と判定される。
ssl_ciphers 'HIGH !aNULL !eNULL !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED !RSA';
# Cipher Strength を 100 にするためには AES128 など 128bit 以下の暗号を除外する必要がある。
#ssl_ciphers 'HIGH !aNULL !eNULL !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED !RSA !AES128';
# OpenSSL v1.1.1 以上では !ARIA128 も追加で除外する必要がある。
# OpenSSL v1.1.1 以上で、かつ TLSv1.3 を有効にした場合、 /etc/ssl/openssl.cnf にも修正が必要 (後述) 。
#ssl_ciphers 'HIGH !aNULL !eNULL !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED !RSA !AES128 !ARIA128';
# nginx v1.19.4 以降であれば、下の設定で TLSv1.3 用の暗号スイートも設定できるので、 openssl.cnf の修正は不要。
#ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384;
# 2019-08-31 時点、 CBC 暗号スイートが WEAK と判定される。 (ただしスコアに影響はでない)
# CBC を除外するには !SHA1 !SHA256 !SHA384 を追加する。
# なお GCM や CHACHA20 暗号スイートの中にも SHA* という名前を持つものがあるが、これらは除外されない。
# 参考: https://security.stackexchange.com/a/207812
# CBC が WEAK となった経緯: https://security.stackexchange.com/questions/210072/why-does-ssl-labs-now-consider-cbc-suites-weak
#ssl_ciphers 'HIGH !aNULL !eNULL !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED !RSA !AES128 !ARIA128 !SHA1 !SHA256 !SHA384';
# DHE 暗号方式のためのパラメータファイルを指定する。
# このファイルは `openssl dhparam 2048 -out dhparam.pem` コマンドで生成できる。
# 2048bit 以上が推奨されている。
# A 評価にするためには 2048bit 以上で作成する必要がある。
# Key Exchange を 100 にするためには 4096bit 以上で作成する必要がある。
ssl_dhparam /path/to/dhparam.pem;
# Key Exchange を 100 にするためには secp384r1 を指定することが必要。
# 指定しなくても A (A+) 評価は可能。
#ssl_ecdh_curve secp384r1;
# どの暗号化スイートを使うか、サーバ側が決定するようにする。
# クライアントが脆弱な暗号化スイートを使おうとすることを防ぐ。
ssl_prefer_server_ciphers on;
# ssl_protocols を絞ると、対応するブラウザが減る。
# https://ja.wikipedia.org/wiki/Template:%E3%82%A6%E3%82%A7%E3%83%96%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8BTLS/SSL%E3%81%AE%E5%AF%BE%E5%BF%9C%E7%8A%B6%E6%B3%81%E3%81%AE%E5%A4%89%E5%8C%96
# A 評価にするなら TLSv1 以上に。(ほとんどの携帯電話が非対応に)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Protocol Support を 100 点にするなら TLSv1.2 のみに。 (IE10 以下や Android 4 以下などが非対応に)
# OpenSSL v1.1.1 以上であれば、 TLSv1.3 を追加しても良い。
#ssl_protocols TLSv1.2;
# Session resumption (caching) を有効にする。
ssl_session_cache shared:SSL:10m;
# OCSP Staplingを有効にする。
# OpenSSL のバージョンが古すぎると、 "ssl_stapling" ignored というエラーが出る。
# OpenSSL のバージョンをアップデートすること。
# 例えば CentOS 5 だとアップデートしきっても古いままなので、有効にはできない。
ssl_stapling on;
ssl_stapling_verify on;
# OCSP Stapling で使用する証明書。
# 中間証明書~ルート証明書の順に結合したファイルを指定する。
# COMODO の PositiveSSL ならば、送付される証明書に含まれる
# COMODORSADomainValidationSecureServerCA.crt
# COMODORSAAddTrustCA.crt
# AddTrustExternalCARoot.crt
# の 3 つを、この順に結合する。
# 例)
# cat COMODORSADomainValidationSecureServerCA.crt \
# COMODORSAAddTrustCA.crt \
# AddTrustExternalCARoot.crt \
# > trusted.crt
#
# Let's Encrypt なら chain.pem を指定する。
ssl_trusted_certificate /path/to/chain.pem;
OpenSSL >= v1.1.1 かつ TLS v1.3 を有効にした状態で満点を取得する場合
OpenSSL v1.1.1 で TLS v1.3 を有効にすると
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
という暗号スイートが TLS v1.3 用に追加されます。
このうち TLS_AES_128_GCM_SHA256
は鍵長が 128bit であるため、 Cipher Strength のスコアが落ちます。
TLS_AES_128_GCM_SHA256
を無効化すればいいのですが、 nginx からでは TLS v1.3 用の暗号スイートを設定できません。
※ TLS v1.3 で使用される暗号スイートは、それ以外の暗号スイートと全く別に管理されるため、 ssl_ciphers
で設定できません。
※ 2018-12-05 nginx v1.15.7 時点。
※ nginx v1.9.14 以降は設定できるようになりました。↑にその設定方法を記述してあります。 openssl.cnf の修正は不要です。
TLS v1.3 用の暗号スイートは openssl.cnf
(通常 /etc/ssl/openssl.cnf
にあるはず) を修正することで設定できます。
openssl.cnf
を開き、最上部に以下の通り追記します。
openssl_conf = default_conf
[default_conf]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
ciphersuites = TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384
ciphersuites
に TLS v1.3 で使用する暗号スイートを列挙します。
修正後、 nginx を再起動 (reload ではなく) することで適用されます。
参考: #1529 (Could not configure TLS1.3 ciphers in OpenSSL 1.1.1 pre4) – nginx
なおスコアには関係しませんが、 AES より ChaCha のほうがパフォーマンスが良いらしいので (未検証) 、 ChaCha を先に指定しています。
参考: #1445 (OpenSSL - ChaCha prioritized - Nginx enhancement) – nginx
参考: Use ChaCha only if prioritized by clnt by tmshort · Pull Request #4436 · openssl/openssl
参考: Do the ChaCha: better mobile performance with cryptography
TLS_AES_128_GCM_SHA256
無効化について
TLS_AES_128_GCM_SHA256
を無効化すると、 Qualys SSL Server Test で以下のようなエラーメッセージが表示されます。(2019-04-04 時点)
This server does not support the mandatory cipher suite TLS_AES_128_GCM_SHA256 for TLS 1.3. See RFC 8446 for details.
これは、 TLS v1.3 の仕様上 TLS_AES_128_GCM_SHA256
が必須であるためです。
しかし、 TLS_AES_128_GCM_SHA256
が有効だと Cipher Strength のスコアは落ちます。
このあたりは調整中らしいです。(See https://github.com/ssllabs/ssllabs-scan/issues/636#issuecomment-461727819)
※ 2022-06-08 時点において、上記エラーメッセージは表示されなくなっていました。
仕様を正しく実装することのほうが重要かと思いますので、満点を目指すのはやはり趣味・実験・自己満足に収めたほうがいいかと思います。