株式会社ハートビーツのITインフラエンジニアがお届けするnginx連載の6回目。今回はnginxのTLS/SSLについての設定を確認していきます。以降、"TLS/SSL"のことを単に"SSL"と書きます。
TLS/SSLの設定
nginx.orgのパッケージからインストールしたnginxが提供している設定ファイルexample_ssl.confをサンプルとして説明します。なお、一部修正をしております。
server { listen 443; server_name example.jp; ssl on; ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key; ssl_protocols SSLv3 TLSv1; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; location / { root /usr/share/nginx/html; index index.html index.htm; } }
SSLの基本設定
listenディレクティブとserver_nameディレクティブについては「nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定」で説明したので、詳しくはそちらを参照してください。
listenディレクティブ
listenディレクティブにはSSLで待ち受けるポート番号を明示的に指定します。次のように通常は443を指定します。
listen 443;
listenディレクティブにsslパラメータを付けると、そのポートでSSLを有効にして待ち受けるようになります。そのポートに関して後述するsslディレクティブをonにしたのと同じ動作になるため、sslディレクティブの記述は不要になります。
listen 443 ssl;
server_nameディレクティブ
server_nameディレクティブではSSLのサーバ証明書で指定したCN(Common Name)と同じサーバ名を指定します。
server_name example.jp;
SSLを有効化 - ssl
sslディレクティブをonに設定すると、SSLが有効になります。ただし、listenディレクティブでsslパラメータを指定したときには不要です。
ssl on;
サーバ証明書とプライベート鍵の指定 - ssl_certificateとssl_certificate_key
ssl_certificateディレクティブにサーバ証明書のファイルのパスを、ssl_certificate_keyディレクティブにプライベート鍵のファイルのパスを指定します。
ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key;
以上の設定をまとめると次のようになります。これらの設定を行えばSSLを利用できます。
server { listen 443; server_name example.jp; ssl on; ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key; }
暗号に関する設定
使用するTLS/SSLのバージョンや暗号スイートについてはデフォルトの設定でも利用できますが、明示的に設定してみましょう。
使用するTLS/SSLのバージョン - ssl_protocols
ssl_protocolsには使用するSSLのバージョンを記述します。設定できるバージョンはSSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2です。
ただし、TLSv1.1とTLSv1.2はnginx 1.1.13以降および1.0.12以降でかつOpenSSL 1.0.1以降のときのみ動作します。
ssl_protocols SSLv3 TLSv1;
使用する暗号スイート - ssl_ciphers
ssl_ciphersにはSSLで使用する暗号スイートを指定します。デフォルト値はnginxのバージョンによって異なりますが、nginx 1.2.0では"HIGH:!ADH:!MD5"になります。指定できる暗号スイートはciphers(1) - OpenSSL
を参照してください。「HIGH(公開鍵暗号の鍵長が128ビットより大きい)」、「aNULL(認証を提供しない暗号スイート)でない」、「MD5でない」ものを指定するにはと次のように記述します。
ssl_ciphers HIGH:!aNULL:!MD5;
参考までに、"openssl ciphers cipherlist '暗号スイートのリスト' -v"コマンドで利用できる暗号スイートの一覧を表示することができます。
$ openssl ciphers cipherlist 'HIGH:!aNULL:!MD5' -v 略 AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 CAMELLIA256-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(256) Mac=SHA1 PSK-AES256-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(256) Mac=SHA1 AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 CAMELLIA128-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(128) Mac=SHA1 PSK-AES128-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA1 略
サーバが示した暗号スイートの優先 - ssl_prefer_server_ciphers
ssl_prefer_server_ciphersをonに指定すると、利用する暗号を選ぶ際に、SSLv3やTLSではサーバが示した暗号スイートが優先されます。offにするとクライアントのものが優先されます。デフォルトはoffです。onにするには次のように記述します。
ssl_prefer_server_ciphers on;
これはnginxの機能というよりはOpenSSLの機能で、SSL_CTX_set_options()にSSL_OP_CIPHER_SERVER_PREFERENCEを設定します。
SSLセッションキャッシュ
サーバの負荷を削減するために、SSLのセッションキャッシュを利用する設定を行います。
SSLセッションキャッシュの種類とサイズの指定 - ssl_session_cache
ssl_session_cacheにはSSLセッションキャッシュをどのように扱うかとそのキャッシュサイズを指定します。次のような文字列を指定することができます。
off | セッションの再利用を明示的に禁止 |
none | クライアントにはセッションの再利用を明示的には禁止しないが、実際は利用不可 |
builtin | OpenSSL組み込みを利用。一つのワーカープロセスのみが利用可能。 |
shared | すべてのワーカープロセスで共有。「shared:名前:サイズ」の形式で記述。 |
デフォルトはnoneです。
サーバの負荷を削減するためにはsharedを使うのが望ましいです。例えば、キャッシュサイズを10MBに設定するには次のように記述します。
ssl_session_cache shared:SSL:10m;
SSLセッションキャッシュのタイムアウトの指定 - ssl_session_timeout
ssl_session_timeoutディレクティブにはSSLセッションキャッシュに保管するSSLセッションの情報のタイムアウト時間を指定します。デフォルトは"5m"(5分)です。例えば、10分に設定するには次のように記述します。
ssl_session_timeout 10m;
設定TIPS
HTTPとHTTPSの設定を共有
上述しましたが、listenディレクティブにsslパラメータを付けると、そのポートでSSLを有効にして待ち受けるようになります。この機能を使い、次のようにsslパラメータを付けない80番ポートを指定したlistenディレクティブとsslパラメータを付けた443番ポートを指定したlistenディレクティブを設定すると、同じバーチャルサーバの設定でHTTPとHTTPSの両方を有効にすることができます。
server { listen 80; listen 443 ssl; server_name example.jp; ssl_certificate /etc/nginx/cert.pem; ... }
このときにはsslディレクティブを記述しないでください。TLS/SSLの有効・無効はlistenディレクティブのsslパラメータの有無で判断するようになります。もし、sslディレクティブでonを指定すると80番ポートでもTLS/SSLで待ち受けるようになってしまいます。
IPベースのバーチャルサーバ
TLS/SSL対応のIPベースのバーチャルサーバを複数持つためには、次のようにバーチャルサーバ毎に待ち受ける異なるIPアドレスをlistenディレクティブに指定します。
server { listen 192.0.2.1:443; server_name example.jp; ssl on; ssl_certificate /etc/nginx/cert-example.jp.pem; ... } server { listen 192.0.2.2:443; server_name example.com; ssl on; ssl_certificate /etc/nginx/cert-example.com.pem; ... }
名前ベースのバーチャルサーバ
従来のTLS/SSLのプロトコルでは、ハンドシェイクの際にクライアントはURIのホスト名の情報をサーバに渡すことができないため、サーバはどのバーチャルサーバに対するリクエストが判断できませんでした。そのため、名前ベースのバーチャルサーバは利用できませんでした。しかし、Server Name Indication(以降、単にSNIと呼ぶ)というTLSの拡張機能により、ハンドシェイクの際にホスト名の情報を送ることができるようになりました。ただし、このSNIを利用するためには、サーバとクライアントの両方がSNIをサポートしている必要があります。なお、Server Name Indication - Wikipediaにサポート状況が掲載されています。クライアントにWindows XPの環境が残っている限り、実質的にSNIのサポートは難しいと思われます。
nginx自体はSNIに対応していますが、SNIの機能を有効にしてビルドされている必要があります。SNIの機能が有効であるかは次のようなコマンドを実行して、"TLS SNI support enabled"という文字列が出力されるかでわかります。
$ nginx -V 2>&1 | grep SNI TLS SNI support enabled
SNIが有効であるときには、クライアントがリクエストしたホスト名に対応したバーチャルサーバの設定が適応され、そのサーバ証明書が使われます。
server { listen 443; server_name example.jp; ssl on; ssl_certificate /etc/nginx/cert-example.jp.pem; ... } server { listen 443; server_name example.com; ssl on; ssl_certificate /etc/nginx/cert-example.com.pem; ... }
なお、SNIが無効であるとき、あるいはクライアントがSNIに対応していないときには、デフォルトサーバのバーチャルサーバが適応され、そのサーバ証明書が使われます。
以上でnginxのTLS/SSLの設定についての説明は終わりです。次回はよく使われる設定(認証、アクセス制御、rewriteモジュール等)について説明します。