nginxでのSSL/TLS設定の備忘録

nginxでのSSL/TLS設定の為の備忘録です。(2020年05月時点)
Qualys SSL Labs社が提供されている[SSL Server Test](https://www.ssllabs.com/ssltest/)にて、Aランク以上が取れる事が目標です。

SSL/TLS設定の良いテンプレとして、Mozillaのサイトで設定のジェネレータが提供されています。
↓
[The Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/)
使用しているWebサーバや構成設定（Intermediateがオススメ設定）を選択すると、SSL/TLS設定に必要な情報が出力されます。

Modernにすると、(2020.05時点)TLSv1.3のみ対応、ほぼ最新OS／ブラウザのみサポートする構成となり、OldにするとWinXPまでサポートできる構成になります。コピペするならOldはやめた方がいいと思います。

上記を踏まえ、nginxのserver.confの内容を少し詳細に見ていきます。
前に書いた記事の続きなので、認証局にはLet's Encryptを使用している前提になっています。


**ssl_certificate**
**ssl_certificate_key**

```text:server.conf
ssl_certificate     /etc/letsencrypt/live/example.jp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.jp/privkey.pem;
```
サーバ証明書、中間証明書、秘密鍵のパスを指定します。
nginxではssl_certificateに、サーバ証明書と中間証明書を連結したファイルを指定できます。

**ssl_dhparam**

```text:server.conf
ssl_dhparam         /etc/nginx/ssl/dhparam.pem;
```
後述する暗号化スイート(cipher suite)にて、DHE(DH鍵交換アルゴリズム)を含むものを使用する場合のパラメタファイルを指定します。
nginxバージョン1.11.0より前は、上記のファイルが無くてもデフォルトでパラメタが組み込まれていたようですが、それ以降のバージョンではファイルを指定しないと、DHEを含む暗号化スイートを指定する事ができません。

DHパラメタファイルは以下のコマンドで作成できます。
鍵長は2048ビット以上を指定して下さい。

```
# openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem
```

**ssl_protocols**

```text:server.conf
ssl_protocols TLSv1.2 TLSv1.3;
```
指定されたSSL/TLSプロトコルを有効にします。
SSL3以前のプロトコルはセキュリティホールが存在する為、公開サーバの場合は特別な理由なく指定してはいけません。TLSv1.1以前については、本当に対応が必要なのか(どうしてもWindowsXPのIE6じゃないとダメな何かがあるとか)、検討したうえで。

**ssl_ciphers**

```text:server.conf
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
```
サーバが対応する暗号化スイート(cipher suite)を指定します。
コロン「:」で区切って複数指定が可能です。
名称の先頭に「!」を付加すると除外指定になります。
適用される優先順位は記述順との事です。
ちなみに上記は[The Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/)のIntermediateで出力された設定をコピペしたものです。

**暗号化スイートって何？**
SSL/TLSプロトコルの鍵交換や認証に使う暗号化アルゴリズム／ハッシュ関数の組み合わせの事です。文字列が長ったらしいのはその組み合わせを表している為。

詳しくわかりたい場合は、こちら↓のサイトが非常に良いと思います。
[理解してるつもりの SSL/TLS でも、もっと理解したら面白かった話](http://tkengo.github.io/blog/2015/12/01/https-details/)
[httpsだからというだけで安全？調べたら怖くなってきたSSLの話!？](https://qiita.com/kuni-nakaji/items/5118b23bf2ea44fed96e)


セキュリティ強度とパフォーマンスのトレードオフがあるので、理解しないまま優先順位を変えるべきではありません。(2020年05月時点ではAES256よりAES128を優先しているサイトが多いようです。状況により都度アップデートしてください。)

尚、サーバが対応していない暗号化スイートを指定するとサーバ起動時にエラーします。対応している暗号化スイートは以下のコマンドで確認できます。

```
$ openssl ciphers -v
```

ssl_ciphersの設定をコピペして動作しない場合は上記コマンドの結果に含まれない暗号化スイートを指定していないかを確認して下さい。

**ssl_prefer_server_ciphers**

```text:server.conf
ssl_prefer_server_ciphers on;
```
サーバー側が指定した暗号化スイートを、クライアント指定よりも優先して使用します。ONにしないと、クライアント側が指定した暗号化スイートが使用されようとするのでセキュリティホールになり得ます。（上記`ssl_protocols`や`ssl_ciphers`の指定が無意味になります。）

**add_header Strict-Transport-Security**

```text:server.conf
add_header Strict-Transport-Security "max-age=63072000" always;
```

> [HTTPヘッダー：Strict-Transport-Security](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Strict-Transport-Security)

> HTTP の Strict-Transport-Security レスポンスヘッダー (しばしば HSTS と略されます) は、ウェブサイトがブラウザーに HTTP の代わりに HTTPS を用いて通信を行うよう指示するためのものです。

> HTTP の Strict Transport Security ヘッダーは、ブラウザーに対してサイトを HTTP を使用して読み込まず、サイトへのすべてのアクセスを、自動的に HTTP から HTTPS リクエストに変換するよう指示することができます。

HTTP→HTTPSリダイレクトでは最初にHTTP(暗号化されていない)通信が発生する時点でクライアントにセキュリティリスクがあるので、ブラウザに対して「HTTPSでサイトを読み込んでね」という指示を、HTTPヘッダーに追加する設定です。

**ssl_session_cache**
**ssl_session_timeout**

```text:server.conf
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
```
nginx公式サイトより、sharedキャッシュのみを使用するのが効率的との事なのでそのように指定します。1mで約4000セッション分のパラメタを格納できるとの事です。
タイムアウトはMozillaのIntermediate設定では1dとなりますが、一般的なサイトであればnginxデフォルトの5mか、10mで良いのではと思います。(長ければ長いほどセキュリティリスクが高くなります)