技術   NginxSSLセキュリティ

Qualys SSL Server Test で A+ 評価を取れるように Nginx の設定を変更する

Nginx の設定を変更する

Nginx の設定をいじる前にまずは、Qualys SSL Server Test で現状の評価を見てみます。
設定変更前の評価
結果、「B」でした!他のブログでは「F」スタートの人とかいたのでまだ高い方?なのかもしれません。というかSSLを導入している状態ではこの評価が最低なのかもしれません。評価の色が黄色で表示されているとどこか不安になってしまいます。
この結果の時の Nginx の設定は下記のようになります。

変更前の設定

設定を変更する前の Nginx の設定ファイルは下記のようにしていました。

変更後の設定

設定変更した後の Nginx の設定ファイルは下記のようになりました。あまり綺麗にかけなくてすいません。

変更後の評価を見てみます。
設定変更後の評価
「A+」をいただきました!やっぱり緑で表示されていないと安心できないですね。無事良い評価をいただけたので、この後は設定した内容の解説をしていきます。

目次へ戻る

Nginxの設定内容を解説

前章で設定した Nginx の設定を解説していきます。

SSLの基本設定

SSL の基本的な設定をしていきます。

  • listen ディレクティブ
    listen 443 ssl http2;
    SSL のポート番号(通常は443)を明示的に指定します。
    ssl」パラメーターを設定すると、設定したポートでの全ての接続で SSL を有効にすることができます。また、この設定をすると後述4の ssl ディレクティブを on に設定した動作となるため、後述4の設定は不要となります。
    http2」パラメーターを設定すると、HTTP/2 接続を有効にすることができます。
  • server_name ディレクティブ
    server_name webcurtaincall.com;
    server_name ディレクティブには、サーバ証明書を発行するときに指定したコモンネーム(FQDN)と同じものを指定します。
  • ssl_certificate / ssl_certificate_key ディレクティブ
    ssl_certificate <サーバー証明書のファイルパス>;
    ssl_certificate_key <秘密鍵のファイルパス>;
    ssl_certificate ディレクティブには、サーバー証明書ファイルのパスを設定します。ssl_certificate_key ディレクティブには、サーバー証明書を発行するときに使用した秘密鍵のファイルパスを指定します。
  • ssl ディレクティブ
    ssl on;
    on にすることで、SSL を有効にすることができます。ただ、前述1で説明した通り、listen ディレクティブで ssl パラメーターを設定済みの場合はこの設定は不要となります。

レスポンスヘッダの設定

レスポンスヘッダに追加していきます。

  • HSTS(HTTP Strict-Transport-Security)の設定
    下記サイトを参考にしました。
    HTTPSを使うなら“HSTS”と“HSTSプリロード”でセキュリティを高めよう
    常時SSL化(https)するときのHSTS設定の方法と注意点
    add_header Strict-Transport-Security 'max-age=31536000;includeSubDomains;preload';
    レスポンスヘッダに Strict-Transport-Security を追加します。これを設定することでクライアントのブラウザに対して、max-age で設定した期間中(今回は1年間に設定)、HTTPS で必ず接続するように指示することが出来ます。また、includeSubDomains を設定することでサブドメインに対しても同時に設定することが出来ます。

    ただしこの設定は、レスポンスヘッダを受け取ってから初めて適応されるため、初回アクセス時には適応されません。そこで、プリロード HSTS という仕組みが存在します。この仕組みは、HSTS の設定を適用していることを予めブラウザが知っていれば、初回アクセス時から HTTP を使うことなく HTTPS で接続出来るというものです。

    プリロード HSTS への登録はこのフォームから出来ます。登録が完了すれば、Google Chrome、Firefox、Safari の3つのブラウザからアクセスした場合、初回アクセス時を含めて常に HTTPS でのアクセスを標準にすることが出来ます。

    プリロード HSTS 登録時の注意点としては、下記の通りになります。
    • サブドメイン単位ではなく、ペイレベルドメイン単位でしか登録出来ない。
    • 有効な HTTPS 証明書が無い場合、サイト(全てのサブドメインを含める)にアクセスすることが出来なくなる。
    • サイト内の全ページが HTTPS 化されている必要がある。サブドメインでサイトを運用している場合はサブドメインも含めて全て HTTPS 化されている必要がある。
    • 最大有効期限(max-age)は少なくとも31536000秒(1年間)は必要である。
    • includeSubDomains ディレクティブを指定する必要がある。
    • preload ディレクティブを指定する必要がある。
    プリロード HSTS への登録は、一度追加すると簡単には削除することは出来ない(反映されるまでに数ヶ月かかるとも)ので、サブドメインを含めて長期的に HTTPS 運用が可能な場合にのみ登録することをオススメします。
    削除用のフォームも一応載せておきます。
  • X-XSS-Protectionの設定
    add_header X-XSS-Protection "1; mode=block";
    クロスサイトスクリプティング(XSS)に対するフィルタ機能を強制的に有効にする設定となります。
  • X-Content-Type-Optionsの設定
    add_header X-Content-Type-Options nosniff;
    Internet Explorer に対して、MIME Sniffing 機能を禁止し、誤った content-type として解釈することを防止する設定になります。
  • X-Frame-Optionsの設定
    add_header X-Frame-Options SAMEORIGIN;
    iframe などの内部に自分のサイトを表示する許可を設定出来ます。DENY もしくは SAMEORIGIN を指定することで自分のサイトのコンテンツが他のサイトに埋め込まれることを禁止でき、クリックジャッキング攻撃を防止することが出来ます。

暗号に関する設定

使用する TLS/SSL のバージョンや暗号スイートについて設定していきます。

  • ssl_prefer_server_ciphersディレクティブ
    ssl_prefer_server_ciphers on;
    ssl_prefer_server_ciphers を on に設定すると、利用する暗号スイートを選択する際に、クライアントの設定ではなく、サーバーで設定した暗号スイートが優先されるようになります。デフォルトは off なので、クライアントの設定に従うことになります。

    この機能は、nginx というよりは OpenSSL の機能で、SSL_CTX_set_options に SSL_OP_CIPHER_SERVER_PREFERENCE を設定することになります。
  • ssl_protocolsディレクティブ
    ssl_protocols TLSv1.2;
    使用する SSL のバージョンを設定します。設定できるバージョンは、SSLv2、SSLv3、TLSv1、TLSv1.1、TLSv1.2、TLSv1.3 で、デフォルトが ssl_protocols TLSv1 TLSv1.1 TLSv1.2; となっています。

    2018年7月20日現在、クレジットカード周りのセキュリティ強化のため、TLS1.0、TLS1.1 のサポート終了が各地で順次実施されており、脆弱性が確認されていない唯一のバージョンである TLSv1.2 のみにするのが現状ベストなため、他のバージョンは排除とします。

    なお、TLSv1.3 について、設定すること自体は出来るみたいですが、どうやら【tattch】のサーバーは openssl のバージョンが足りてないせい?で、うまくいかないので今回は TLS1.2 までとしました。
  • ssl_ciphersディレクティブ
    ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
    使用する暗号スイートを設定します。ここについては結構複雑で、知識が全然足りていないので、下記を参考に設定しました。
    Strong SSL Security on nginx
  • ssl_dhparamディレクティブ
    ※ Nginx のバージョン1.11.0 のチェンジログより DHE 暗号を使用する場合には設定が必要となったとのこと。
    ssl_dhparam <DHキーのパス>;
    ECDHE(Ephemeral Elliptic curve Diffie–Hellman) 暗号アルゴリズムで使用する DH キーを指定する設定です。Nginx のデフォルトは1024バイトの DH キーを使用するため、推奨されている2048バイト以上の DH キーを新たに作成し設定します。今回は4096バイトのものを下記の通りに生成しました。
    ※ 生成には少し時間がかかります(8分くらいかかりました)。
    # cd /etc/nginx/
    # mkdir ssl
    # cd ssl
    # openssl dhparam -out dhparam.pem 4096
    Generating DH parameters, 4096 bit long safe prime, generator 2
    This is going to take a long time
    ...
    

SSLセッションキャッシュの設定

SSL セッションキャッシュを有効にすると2回目以降の接続に初回接続で使用したセッションを再利用して接続するようになるため、サーバーの負荷軽減が期待できます。
ssl_session_cache にはいくつか設定可能なパラメーターが存在しますが、全ワーカープロセス間で共有されるキャッシュを使用する shared に設定しました。

当サイトは規模が小さいのでとりあえず、ssl_session_timeout のSSL セッションタイムアウト時間の設定と合わせて下記のように設定しました。状況に応じて変更していきます。
ちなみに1MBにつき約4000セッションを保存することが可能とのことです。

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 1h;

OCSP Staplingの設定

※ Nginx のバージョン1.3.7以上で OCSP Stabling の設定が可能となります。
OCSP Stapling(Online Certificate Status Protocol)の設定を有効にすると、Nginx はブラウザに代わって OCSP 要求を行うようになります。OCSP サーバから受信した応答は Nginx のブラウザレスポンスに追加され、OCSP サーバに直接接続することでブラウザがサーバー証明書の失効ステータスを確認する必要がなくなります。

  • OCSP(Online Certificate Status Protocol)とは?
    サーバー証明書が正当なものかどうかを確認するためのプロトコルです。従来は、サーバー証明書の失効を確認するために署名所失効リスト(CRL)が利用されていましたが、リストが巨大化しダウンロードに時間がかかってしまうため、現在では OCSP を利用してサーバー証明書の失効を確認するのが一般的です。

    OCSP を利用する懸念点としては、OCSP 要求を実行する場合、サードパーティの OCSP responder に対して実行する必要があり、レイテンシ(遅延)や通信に失敗する可能性があります。そこで登場するのが、OCSP Stapling という機能になります。TLS ハンドシェイク中にキャッシュされた OCSP レコードをサーバーが送信出来るようにすることで、OCSP responder をバイパスすることになり、クライアントと OCSP responder 間のラウンドトリップ時間をなくすことができます。
  • 設定方法
    下記のように設定します。
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate <サーバー証明書を証明する認証局のルート証明書のパス>;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    • ssl_stapling ディレクティブ
      OCSP Stapling を有効にするかどうかを設定します。on にすると有効になります。
    • ssl_stapling_verify ディレクティブ
      OSCP の問い合わせ結果の検証を実施するかどうかを設定します。on にすると有効になります。
    • ssl_trusted_certificate ディレクティブ
      サーバー証明書を証明する認証局のルート証明書等のファイルパスを指定します。【tattch】は今回さくらの JPRS でサーバー証明書を発行したので、JPRS のルート証明書を指定しました。ここからダウンロードすることが出来ます。
      もし、Let's Encrypt を利用している場合は chain.pem ファイルのパスを指定すれば OKとのこと。
    • resolver ディレクティブ
      名前解決の際に利用する DNS サーバーを指定します。Google Public DNS(プライマリ: 8.8.8.8、セカンダリ: 8.8.4.4)を指定しました。valid パラメーターには DNS サーバーへ名前解決を実行する時間を指定します。デフォルトでは指定した DNS サーバーで名前解決結果をキャッシュしておく時間、Time To Live(TTL)の値となります。キャッシュして欲しくない場合は、0 を指定すると毎回 DNS サーバーへと名前解決を実行しに行くことになります。
    • resolver_timeout ディレクティブ
      名前解決のタイムアウト時間を設定します。

OCSP Stapling の設定が出来ているかどうかは下記コマンド例にて確認することが出来ます。例は TLSv1.2 を使用した場合です。
※ Nginx の設定環境によって使用するプロトコルは変更してください。無効なプロトコルを使用した場合は例の通りにはいかないです。

# 失敗している場合
$ openssl s_client -connect <ドメイン名>:443 -tls1_2 -status -reconnect 2>&1 < /dev/null | grep OCSP
OCSP response: no response sent

# 成功している場合
$ openssl s_client -connect <ドメイン名>:443 -tls1_2 -status -reconnect 2>&1 < /dev/null | grep OCSP
OCSP response:
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
        Subject: C=JP, O=Japan Registry Services Co., Ltd., CN=JPRS Domain Validation Authority - G2 OCSP Responder
            OCSP No Check:
                OCSP Signing

その他変更点

その他に変更した点を解説していきます。

  1. リダイレクトの記述を追加
    server {
        listen 80;
        server_name webcurtaincall.com;
        return 301 https://$server_name$request_uri;
    }
    http でのアクセスは全て https へリダイレクトするようにします。
  2. proxy_set_headerディレクティブ
    • Host パラメーター
      # 変更前
      proxy_set_header Host $http_host;
      
      # 変更後
      proxy_set_header Host $host;
      Host header forgery 脆弱性対策として、$http_host ではなく、$host を使用すべきとのこと。
      ただし、他にも対策が必要とのことで、詳細は参考サイトを参照してください。
    • X-Forwarded-Proto パラメーター
      # 変更前
      proxy_set_header X-Forwarded-Proto \$scheme;
      
      # 変更後
      proxy_set_header X-Forwarded-Proto https;
      変更前は、受けたリクエストのプロトコルを X-Forwarded-Proto に設定するようにしていましたが、当サイトは常時 SSL としましたので https とします。
    • proxy_redirect パラメーター
      # 変更前
      proxy_redirect off;
      
      # 変更後
      proxy_redirect http:// https://;
      常時 SSL 化に伴い http でのアクセスは https へリダイレクトするようにします。
目次へ戻る

終わりに

少し期間が空いてしまいましたが、Nginx の記事第2弾でした。評価は「A+」を取れましたが、調べているとまだまだ設定が足りてない感じです。セキュリティ周りは一生考えないといけない問題だと思いますので、今後も設定した方が良い設定や間違っている設定を発見次第、追加・修正していきたいと思います。

目次へ戻る