Webサーバー nginx における SSL証明書設定の安全性向上 ~SSL Server Test で A+ 判定を目指して~

はじめに

SSL証明書に使われる暗号化方式は設定時には安全と判断しても、日が経ってから脆弱性が発覚するものです。 脆弱性が発覚した暗号化方式は以後使えなくなるよう、無効にする必要があります。 今回、CentOS7 + Nginx における設定の調整方法と、安全性の確認には QUALYS SSL LABS の SSL Server Test ツール (https://www.ssllabs.com/ssltest/index.html) による安全性の確認を紹介したいと思います。 前提として、CentOS7 + Nginx にはすでに SSL証明書がインストール済みで、https://~ でアクセスできる状態にしておいてください。こちらの投稿を参照してください。

時間がない人のために

調整が完了した nginx の設定内容です。この設定は対応するクライアント(ブラウザ)の互換性よりも、安全性を優先しています。 そのため、Android 4.3 以前の標準ブラウザーや、IE10 以前のブラウザー、Java7 以前の Java プログラムなどからはアクセスできなくなる可能性があります。 サポートするクライアント (ブラウザー) をできる限り多くしたい場合は、本投稿の末尾にいくつかバリエーションを載せていますので、参考にしてください。
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ECDH !aNULL !eNULL !SSLv2 !SSLv3';
    add_header  Strict-Transport-Security "max-age=31536000; includeSubdomains";

    (後略)

設定の調整方法

現時点 (2015.09.27) での判定が A+ となるような nginx での設定を調査してみました。

調整前の安全性確認

nginx の SSL証明書に関する設定は最小限で、ssl on、ssl_certificate、ssl_certificate_key の 3 行のみでした。 まずは、現状の安全性を確認しました。結果はランク C。
  • Certificate: 100
  • Protocol Support: 70
  • Key Exchange: 80
  • Cipher Strength: 90
SSLv3 をサポートしていると、ランクの上限が C になったようです。 「This server is vulnerable to the POODLE attack. If possible, disable SSL 3 to mitigate. Grade capped to C.」

SSLv2、SSLv3の無効化

Cipher の指定だけで単純に SSLv3 を無効にするとランクが F に落ちてしまいました。
  • Certificate: 100
  • Protocol Support: 70
  • Key Exchange: 0
  • Cipher Strength: 90
匿名の認証方式が有効になってしまったようです。 「This server supports anonymous (insecure) suites (see below for details). Grade set to F.」
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ALL !SSLv2 !SSLv3';

    (後略)

匿名の認証方式の無効化

匿名の認証方式を無効にしたところ、ランクが B に上昇しました。
  • Certificate: 100
  • Protocol Support: 70
  • Key Exchange: 80
  • Cipher Strength: 90
鍵交換時の暗号化方式に、暗号化強度が弱い暗号化方式が有効になっているため、ランクの上限が B になったようです。 「This server supports weak Diffie-Hellman (DH) key exchange parameters. Grade capped to B.」
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ALL !aNULL !eNULL !SSLv2 !SSLv3';

    (後略)

強度が弱い暗号化方式の無効化

DH 暗号方式を無効化したところ、ランクが A- に上昇しました。
  • Certificate: 100
  • Protocol Support: 100
  • Key Exchange: 90
  • Cipher Strength: 90
Forward Secrecy が無効のため、ランクの上限が A- になったようです。 「The server does not support Forward Secrecy with the reference browsers. Grade reduced to A-.」
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ALL !DH !aNULL !eNULL !SSLv2 !SSLv3';

    (後略)

Forward Secrecy 対応

Forward Secrecy に対応するには、鍵交換時の暗号化方式に ECDH を指定する必要があります。結果、ランクが A に上昇しました。 (参考: SSL Labs: Deploying Forward Secrecy)
  • Certificate: 100
  • Protocol Support: 100
  • Key Exchange: 90
  • Cipher Strength: 90
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ECDH !aNULL !eNULL !SSLv2 !SSLv3';

    (後略)

Strict-Transport-Security ヘッダー対応

Strict-Transport-Security ヘッダー (HSTS) 対応はサイト全体を常に https://~ のみでサービスさせる場合に有効にしておくことで、クライアント(ブラウザー)がこのサイトにアクセスする際、HTTP リクエストになっていた場合でも強制的に HTTPS てアクセスするようになります。結果、ランクが A+ に上昇しました。
  • Certificate: 100
  • Protocol Support: 100
  • Key Exchange: 90
  • Cipher Strength: 90
この対応のおかげで、ランク A+ をもらえるようになりました。 「This server supports HTTP Strict Transport Security with long duration. Grade set to A+.」

    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ECDH !aNULL !eNULL !SSLv2 !SSLv3';
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

    (後略)

付録

本投稿を作成するにあたり、Cipher のフィルター文字列について知っておくと、フィルター文字列をカスタマイズして調整がしやすくなるかと思いましたので、付録として紹介します。

Session resumption (caching) 対応

Session resumption は tickets で対応しているので ID による cashing はサポートしなくてもよいでのですが、これに対応させる設定を紹介します。結果は変わらず、ランク A+ になりました。
  • Certificate: 100
  • Protocol Support: 100
  • Key Exchange: 90
  • Cipher Strength: 90
    (前略)

    ssl_prefer_server_ciphers  on;
    ssl_ciphers  'ECDH !aNULL !eNULL !SSLv2 !SSLv3';
    add_header  Strict-Transport-Security "max-age=31536000; includeSubdomains";
    ssl_session_cache  shared:SSL:10m;
    ssl_session_timeout  10m;

    (後略)

Cipher に指定する文字列の検証

Cipher に指定するフィルター文字列を決める際、実際にどのような暗号化方式が使えるようになるのか確認しておく必要があります。 openssl コマンドには Cipher を指定してリストできる機能がありますので、これを使って作業すると便利です。下記は CentOS7 でリストした結果です。
$ openssl ciphers -v 'ECDH !aNULL !eNULL !SSLv2 !SSLv3' | sort
ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128)  Mac=SHA256
ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256)  Mac=SHA384
ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-RSA-AES128-SHA256  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128)  Mac=SHA256
ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-RSA-AES256-SHA384  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384

Cipher に指定する文字列の作成

Cipher に指定するフィルター文字列は下記のように並べると可読性が上がるかと思います。
  1. 有効にする暗号化方式のリスト。できれば ALL を指定しないようにする。 (例: ALL、ECDH など)
  2. 上記のうち、暗号化方式として無効化するための厳密なリスト。 (例: !DH、!aNULL、!eNULL など)
  3. 上記のうち、プロトコルとして無効化するための厳密なリスト。 (例: !SSLv2、!SSLv3 など)
ざっくり解釈すると、「許可したい暗号化方式をおおまかに決めて、このうち無効化したいものを『!』つきで除外する」、といったところでしょうか。最初に ALL を指定しないようにするのは、無効化したいものを精査しながら指定する手間を減らせる事から、私としてはおすすめの考え方になります。 さらに、「!aNULL !eNULL !SSLv2 (!SSLv3)」はお約束の設定になるかと思いますので、末尾に固定で固めておくとよいでしょう。
(今回、安全性を最重視して設定した Cipher)
'ECDH !aNULL !eNULL !SSLv2 !SSLv3'

(TLSをサポートしないクライアントにも広く対応するよう設定した Cipher の例。ランクは C。)
'RSA ECDH !LOW !EXPORT !3DES !MD5 !aNULL !eNULL !SSLv2'

(IE6/WinXP、IE8/WinXP をサポート対象外にして、上記から安全性を向上させた Cipher の例。ランクは C。)
'RSA ECDH !LOW !EXPORT !3DES !MD5 !RC4 !aNULL !eNULL !SSLv2'

Webサーバー nginx における SSL証明書設定の安全性向上 ~SSL Server Test で A+ 判定を目指して~」への1件のフィードバック

  1. ピンバック: Let’s Encryptを使って無料でnginxをHTTPS対応する | ゆうちかブログ

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください