Help us understand the problem. What is going on with this article?

Let's EncryptのSSL証明書で、Qualys SSLTestでA+評価を獲得するには

More than 3 years have passed since last update.

前回の記事、「Let's Encryptから無料・安全なSSL証明書を取得してNginxに設定するまで」で、Let's Encryptから無料のSSL証明書を取得する方法を紹介しました。
Let's Encryptは、2015/11/17現在ベータ運用中ではありますが、だからと言って発行されたSSL証明書に問題がある訳ではありません。
その証拠に、Let's Encryptから取得したSSLサーバ証明書をnginxに設定し、Qualys SSL Testで検査したところ、無事「A+」評価が獲得できました。

Assessment Result
(※役に立つかわかりませんが、テスト結果の完全なスクリーンショットも置いておきます。サイズが大きいので注意 / 0.5M)

ちょっと長いですが、設定の手順をご紹介します。
(どちらかというとQualys SSL TestでA+を取る設定についての一般的な話で、Let's EncryptのSSL証明書と余り関係のない内容になっていますが、話の流れとしてご容赦下さい)

Qualys SSLTest とは?

米クオリス社によって提供されているサービスで、サイトのSSL設定をA~Fの分かりやすい点数で評価してくれます。
digicert社によるSSLTestの解説がとても参考になります。

また、私は使ったことはありませんが、API及びコマンドラインの公式クライアントも存在し、これを利用してサイトのSSLチェックの自動化等も可能なようです。
Qualys SSLTest Command-line client

動作確認環境

  • Ubuntu 14.04 Trusty 64-bit on AWS
  • nginx (OpenResty) 1.9.3 + HTTP/2 patch
  • Chrome 46.0.2490.86
  • Qualys SSLTest : SSL Report v1.20.28

設定項目

  1. 弱い暗号形式の無効化
  2. Logjam攻撃対策
  3. OCSPステープリングの有効化
  4. HSTSヘッダー対応 (要注意)
  5. HPKP設定 (要注意)
  6. 透かし入り証明書(Certificate Transparency)設定

設定内容

1.弱い暗号形式の無効化

この設定項目が一番重要です。この内容如何で、評価は「F」から「A」に上がります。
弱い暗号形式を無効化すれば評価値は上がりますが、その反面、古い環境(例:IE6/XP)で暗号化通信が出来なくなるなどの影響も出ますから、評価値に過度に捉われず、実現したい環境にあった設定するのが良いかと。

設定例

nginx.conf
   #    ssl_ciphers  HIGH:!aNULL:!MD5;
      ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES
256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES
128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-
SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES
256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GC
M-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES
-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
      ssl_prefer_server_ciphers  on;

2.Logjam攻撃対策

Logjam攻撃に対応するため、DH鍵交換に利用する素数のビット数を2,048以上に設定します。

参考: DH鍵交換に存在する脆弱性「Logjam」、HTTPSなどのプロトコルに影響

設定例

# DHPARAMの生成
sudo openssl dhparam -out /etc/ssl/private/dhparams_4096.pem 4096
nginx.conf
ssl_dhparam /etc/ssl/private/dhparams_4096.pem;

3.OCSPステープリングの有効化

設定例

nginx.conf
  # Enable OCSP (Online Certificate Status Protocol) Stapling
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.4.4 8.8.8.8 valid=300s;
  resolver_timeout 10s;

参考

4.HSTSヘッダー対応 (要注意)

サイトにて、http:// にアクセスされた際、https:// に自動で切り替わって欲しい事を、ブラウザに知らせます。
このように動作すると困る・迷惑、という場合は、設定しないように気をつけましょう。

設定例

nginx.conf
  # Enable HSTS (HTTP Strict Transport Security)
  add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

5.HPKP設定 (要注意)

HPKP (HTTP 公開鍵ピンニング)設定ですが、これも要注意です。
鍵の紛失や盗難にあった等の際に、サイトがブラウザに「怪しい」認定され、そのままになる危険があるようです。
HPKPが不正な時のブラウザの表示については、HPKP確認用のテストサイトで実際に見る事ができます。
HPKP failed on Chrome

こちらの解説が大変参考になりました。
公開鍵ピンニングについて

内容を十分理解した上で設定しましょう。

設定する内容はシンプルで、HTTPSサーバの応答ヘッダに以下のような行を含めるだけです。
pin-sha256にBase64エンコードされた公開鍵の情報を含めます。
メインの鍵とバックアップの鍵の、2つの情報が必須です。

Public-Key-Pins: pin-sha256="base64=="; max-age=expireTime [; includeSubdomains][; report-uri="reportURI"]

バックアップの鍵はなかったらこの機会に生成しましょう。

設定例

# メインの鍵の情報を取り出して、Base64符号化
sudo openssl x509 -noout -in /etc/letsencrypt/live/shield.jp/chain.pem -pubkey | \
  openssl pkey -pubin -outform der |\
  openssl dgst -sha256 -binary |\
  base64

# バックアップ鍵の生成
sudo openssl genrsa -out /etc/letsencrypt/live/shield.jp/hpkp-backup.key 4096
sudo openssl req -new -key /etc/letsencrypt/live/shield.jp/hpkp-backup.key -sha256 -out /etc/letsencrypt/live/shield.jp/hpkp-backup.csr

# バックアップ鍵の情報を取り出して、Base64符号化
sudo openssl req -pubkey < /etc/letsencrypt/live/shield.jp/hpkp-backup.csr | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
nginx.conf
  # HPKP Settings
  add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="GO8LTsdpBf/sLaUQ3/NPVCaGzZOmku+6iIBdeef9K2k="; max-age=2592000; includeSubDomains';

参考

6.透かし入り証明書 (Certificate Transparency) 設定

Symantec社によるCertificate Transparency(透かし入り証明書)の解説が分かりやすいです。

設定しないとChromeで見た時に以下のように表示されるのが気になるため、設定することに決めたものの・・・、
No CT provided
(Twitterでも設定していない位なので、問題ないのかもしれませんが)

この設定はかなり面倒でした。

  • nginxにnginx-ctプラグインをインストール
  • ct-submitコマンドの取得とビルド
  • CT情報の登録とSCTの取得

まずはnginxにnginx-ctプラグインをインストールします。
nginxのプラグインは動的に追加できないので、nginxをソースから再設定・リビルドする必要があります。

# nginx-ctプラグインのダウンロード
cd /tmp
wget https://github.com/grahamedgecombe/nginx-ct/archive/master.zip
unzip master.zip

# nginx-ctプラグインを有効化してNginxを再ビルド (OpenSSL 1.0.2以降も必要)
cd /usr/local/src/nginx-1.9.3
./configure --add-module=/tmp/nginx-ct-master --with-http_ssl_module  --with-openssl=/usr/local/src/openssl-1.0.2d
make clean
make
sudo make install

次に、透かし入り証明書情報(Certificate Transparency)をサーバに登録・取得するためのコマンド、ct-submitをインストールします。
ビルドのためにGoも必要です。

cd /tmp
wget https://github.com/grahamedgecombe/ct-submit/archive/master.zip
unzip master.zip
cd ct-submit-master
go build
sudo install -s -m755 ./ct-submit-master /usr/local/bin/ct-submit

今度はct-submitコマンドを使って、X509証明書情報をCTログサーバに送信します。
※スクリプト先頭部分のKEY, CTSUBMIT, SCTS_DIR, $SCTS_DIRの許可件等は適切に調整して下さい。
(一部のサーバからはエラーが返ってきたのでコメントアウトしました)

ct-submit.sh
#!/bin/sh
# Let's encryptから入手した fullchain.pem の場所
KEY=/etc/letsencrypt/live/shield.jp/fullchain.pem
# CT情報の保存先
SCTS_DIR=/etc/letsencrypt/live/shield.jp/scts
# ct-submitコマンド
CTSUBMIT=/usr/local/bin/ct-submit

echo 1
sudo sh -c "$CTSUBMIT ct.googleapis.com/aviator \
<$KEY \
>$SCTS_DIR/aviator.sct"
echo 2
sudo sh -c "$CTSUBMIT ct.googleapis.com/pilot \
<$KEY \
>$SCTS_DIR/pilot.sct"
echo 3
sudo sh -c "$CTSUBMIT ct.googleapis.com/rocketeer \
<$KEY \
>$SCTS_DIR/rocketeer.sct"
#echo 4
#sudo sh -c "$CTSUBMIT ct1.digicert-ct.com/log \
#<$KEY \
#>$SCTS_DIR/digicert.sct"
#echo 5
#sudo sh -c "$CTSUBMIT ct.izenpe.com \
#<$KEY \
#>$SCTS_DIR/izenpe.sct"
#echo 6
#sudo sh -c "$CTSUBMIT log.certly.io \
#<$KEY \
#>$SCTS_DIR/certly.sct"

指定したディレクトリにSCTファイルが出力されているか確認しましょう。
(SCT = Signed Certificate Timestamp:登録済み証明書タイムスタンプ)

sudo ls -al /etc/letsencrypt/live/shield.jp/scts
total 20
drwxr-xr-x 2 root root 4096 Nov 12 16:54 .
drwxr-xr-x 3 root root 4096 Nov 12 17:46 ..
-rw-r--r-- 1 root root  118 Nov 12 16:54 aviator.sct
-rw-r--r-- 1 root root  119 Nov 12 16:54 pilot.sct
-rw-r--r-- 1 root root  118 Nov 12 16:54 rocketeer.sct

以上で完了です。
あとはnginxを再起動してから、ChromeでHTTPSのURLにアクセスし、アドレスパーの緑の部分をクリックして確認しましょう。
以下のように、サーバからCT情報が提供されたということが表示されればOKです。

CT Provided

設定例

nginx.conf
  # nginx-ctプラグインを有効にしていないとエラーになります
  ssl_ct on;
  ssl_ct_static_scts /etc/letsencrypt/live/shield.jp/scts;

参考

Certificate Transparentのログサーバの一覧はどこから手に入る?
http://esupport.trendmicro.com/media/13357571/CT%20FAQ.pdf
答: 以下から入手可能。
http://www.certificate-transparency.org/known-logs

最後に

改めてnginx.confの設定内容です。少しずつ紹介した項目をひとまとめにしました。

nginx.conf
    #
    # HTTPS server
    #
    server {

      listen       443 ssl http2; # HTTP/2パッチを当てているため。通常は http2 は不要
      server_name  shield.jp;

      ssl_certificate /etc/letsencrypt/live/shield.jp/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/shield.jp/privkey.pem;

      ssl_session_cache   shared:SSL:3m;
      ssl_buffer_size     8k;
      ssl_session_timeout 10m;

      # 1. 暗号方式の設定
      # (デフォルト) ssl_ciphers  HIGH:!aNULL:!MD5;
      ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
      ssl_prefer_server_ciphers  on;

      # 2. Logjam攻撃対策
      ssl_dhparam /etc/ssl/private/dhparam_4096.pem;

      # 3. Enable OCSP (Online Certificate Status Protocol) Stapling
      ssl_stapling on;
      ssl_stapling_verify on;
      resolver 8.8.4.4 8.8.8.8 valid=300s;
      resolver_timeout 10s;

      # 4. Enable HSTS (HTTP Strict Transport Security)
      add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

      # 5. HPKP Settings
      add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="GO8LTsdpBf/sLaUQ3/NPVCaGzZOmku+6iIBdeef9K2k="; max-age=2592000; includeSubDomains';

      # 6.証明書透かし (Certificate Transparency)設定
      ssl_ct on;
      ssl_ct_static_scts /etc/letsencrypt/live/shield.jp/scts;

      # 後略
}

これでようやくセキュアなWebサイトが完成しました。
やったね!
・・・それにしても疲れます。
更に、SSLの一つ一つの設定項目を吟味するとなると、膨大な背景知識の網羅が必要となり気が遠くなってきます。
Qualys SSLTestのおかげで、現状安全かどうかをまずは確認できる訳で、本当に有難いサービスだなと実感しました。
素晴らしいサービスの開発者に感謝です。

参考

dseg
フロントエンド開発とシステムプログラミング、言語に興味があります。 趣味は将棋、好きな棋士は豊島さん。好きな戦法は竹部流
https://shield.jp/blog/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした