HTTPSサーバの設定
HTTPSサーバの最適化 SSL 証明書チェーン 単独のHTTP/HTTPSサーバ 名前ベースのHTTPSサーバ 幾つかの名前を持つSSL証明書 Server Name Indication 互換性 |
HTTPSサーバを設定するには、ssl
パラメータがserverブロック内のlistening sockets上で有効にされる必要があり、server certificate とprivate key ファイルの場所が指定されていなければなりません:
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; ... }
サーバ証明書は公開されているものです。サーバに接続する全てのクライアントに送信されます。秘密キーは秘密の存在で、アクセスが制限されたファイルに保存されていなければなりません。nginxのマスタープロセスが読み込めるようでなければなりません。秘密キーは証明書として同じファイルの中に交互に保存されているかもしれません:
ssl_certificate www.example.com.cert; ssl_certificate_key www.example.com.cert;
この場合、ファイルのアクセス権も制限されていなければなりません。証明書とキーは一つのファイルの中に保存されていますが、証明書だけがクライアントに送られます。
ssl_protocols と ssl_ciphersディレクティブは接続がSSL/TLSの強力なバージョンと暗号だけを含むように制限するために使うことができます。 デフォルトでは、nginxは"ssl_protocols TLSv1 TLSv1.1 TLSv1.2
" および "ssl_ciphers HIGH:!aNULL:!MD5
" を使います。ですので、それらを明示的に設定する必要は一般的にありません。これらのディレクティブのデフォルトの値は何回か 変更されたことに注意してください。
HTTPS サーバの最適化
SSL の操作は余分なCPUリソースを消費します。マルチプロセッサーシステム上では、利用可能なCPUコアの数よりも多い、幾つかのworker プロセス が実行されている筈です。もっともCPUに厳しい操作はSSLハンドシェイクです。クライアントあたりのこれらの操作の数を最小限にする方法は2つあります:一つ目はkeepalive接続を有効にして一つの接続で複数のリクエストを送信することです。二つ目はSSLセッションパラメータを再利用して並行あるいは連続する接続のSSLハンドシェイクを避けることです。セッションは、workerで共有されてssl_session_cacheで設定される、SSLセッションキャッシュ内に保存されます。1メガバイトのキャシュには約4000セッションが含まれます。キャッシュのタイムアウトのデフォルトは5分です。このタイムアウトは ssl_session_timeout ディレクティブを使って増やすことができます。下記は、10メガバイトの共有セッションキャッシュを使ったマルチコアシステムに最適化した設定の例です:
worker_processes auto; http { ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; server { listen 443 ssl; server_name www.example.com; keepalive_timeout 70; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; ...
SSL 証明書の連結
あるブラウザではよく知られた認証局の署名について苦情が言われるかも知れませんし、一方で他のブラウザでは問題なく証明書を受け入れるかも知れません。これは、発行局が、あるブラウザに配布されているよく知られている認証局には無い中間認証を使ってサーバ証明書に署名を行ったために起こります。この場合、認証局は、署名されたサーバ証明書に結びつけられる必要がある連鎖証明書のひとかたまりを提供します。サーバ証明書は連結されたファイルの中で連鎖証明書よりも前に現れなければなりません:
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
結果ファイルはssl_certificateディレクティブの中で使われなければなりません:
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.chained.crt; ssl_certificate_key www.example.com.key; ... }
もしサーバ証明書とその束が間違った順番で結びつけられていた場合、nginxは起動に失敗し、次のエラーメッセージを表示するでしょう:
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed (SSL: error:0B080074:x509 certificate routines: X509_check_private_key:key values mismatch)
nginxがサーバ証明書の代わりに秘密キーを束の最初の証明書に使おうとしてエラーが起きます。
ブラウザが中間証明書を受け取り、信頼できる認証局が署名しているような中間証明書は通常保存するため、活発に使われているブラウザは要求される中間証明書をすでに持っていて、連鎖していない証明書に苦情を言わないかも知れません。サーバが確実に完全な証明書の鎖を送るようにするには、openssl
のコマンドラインユーティリティが使われるでしょう:
$ openssl s_client -connect www.godaddy.com:443 ... 鎖状証明書 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc /OU=MIS Department/CN=www.GoDaddy.com /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b) i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 i:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority 2 s:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority i:/L=ValiCert Validation Network/O=ValiCert, Inc. /OU=ValiCert Class 2 Policy Validation Authority /CN=http://www.valicert.com//emailAddress=info@valicert.com ...
SNIを使った設定をテストする場合、openssl
はデフォルトでSNIを使わないため、-servername
オプションを指定することが重要です。
この例では、www.GoDaddy.com
サーバ証明書#0 のsubject("s") は、証明書#1のsubjectである発行人("i")によって署名されています。証明書#1は証明書#2のsubjectである発行人によって署名されています。証明書#2は良く知られている発行人ValiCert, Inc.によって署名されており、ValiCert, Inc.の証明書はブラウザの証明書ベースに保存されています。(それは家においてあったジャックが建てた家に)
もし証明書のまとまりが追加されなければ、サーバ証明書#0だけが表示されるでしょう。
一台のHTTP/HTTPSサーバ
HTTPとHTTPSリクエストの両方を処理する一台のサーバを設定することは可能です。
server { listen 80; listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ... }
0.7.14より前のSSLは上のように個々のlistenソケットを選択的に有効にすることはできませんでした。SSLはssl ディレクティブを使ってサーバ全体で有効にすることしかできず、それが一台でHTTP/HTTPS サーバを設定することを不可能にしていました。listen
ディレクティブのssl パラメータはこの問題を解決するために追加されました。従って最近のバージョンでのsslディレクティブの利用は薦められません。
名前ベースのHTTPSサーバ
二つ以上のHTTPSサーバで一つのIPアドレスをlistenするように設定する場合に良くある問題
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... }
この設定によりブラウザはリクエストしたサーバの名前に関係なく、デフォルトのサーバの証明書、例えばwww.example.com
を受け取ります。これはSSLプロトコルの挙動によっておきるものです。ブラウザがHTTPリクエストを送る前にSSL接続が確立され、nginxはリクエストされたサーバの名前を知りません。従って、デフォルトのサーバ証明書が提供されるだけになるでしょう。
この問題を解決するもっとも健全な方法はそれぞれのHTTPSサーバに個々のIPアドレスを割り当てることです。
server { listen 192.168.1.1:443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 192.168.1.2:443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... }
複数の名前をもつSSL証明書
複数のHTTPSサーバの間で一つのIPアドレスを共有する他の方法があります。しかしながら、それらは全て不利な点があります。一つの方法は、複数の名前、例えば www.example.com
と www.example.org
、がSubjectAltName 証明フィールドにある証明書を使うことです。しかしながら、SubjectAltName フィールドの長さには制限があります。
他の方法は、ワイルドカード名、例えば*.example.org
証明書を使うことです。ワイルドカード証明書は特定のドメインの全てのサブドメインを保障します。しかしトップレベルのみです。この証明書はwww.example.org
に合致しますが、example.org
とwww.sub.example.org
には合致しません。これら二つの方法は組み合わすこともできます。証明書は、SubjectAltName フィールドに正確な名前とワイルドカード名、例えばexample.org
と*.example.org
を含むかも知れません。
全てのサーバに一つのメモリーのコピーが継承されるように、幾つかの名前と秘密キーを持つ証明書を設定のhttpレベルに配置した方が良いです:
ssl_certificate common.crt; ssl_certificate_key common.key; server { listen 443 ssl; server_name www.example.com; ... } server { listen 443 ssl; server_name www.example.org; ... }
Server Name Indication
一つのIPアドレスでいくつかのHTTPSサーバを実行する一般的な解決方法は、TLS Server Name Indication 拡張 (SNI, RFC 6066)で、ブラウザがSSLハンドシェイクの間にリクエストするサーバ名を渡し、サーバが接続のために使う必要がある証明書を知るようにすることができます。SNI は現在のところほとんどの最新のブラウザで サポートされますが、いくつかの古いあるいは特別なクライアントでは使われないかもしれません。
SNIではドメイン名だけを渡すことができますが、幾つかのブラウザはリクエストにIPアドレスが含まれている時に誤って名前としてIPアドレスを渡すかも知れません。これは当てにすべきではありません。
nginxでSNIを使うためには、NGINXライブラリがビルドされた時のOpenSSLライブラリと、実行時に動的にリンクされるライブラリの両方でサポートされていなければなりません。OpenSSLjはバージョン0.9.8fから
$ nginx -V ... TLS SNI support enabled ...
しかしながら、もしSNIが有効になったNGINXがSNIをサポートサポートしていないOpenSSLに動的にリンクされた場合、NGINXは警告を表示します:
nginxがSNIサポートでビルドされたが、tlsextサポートしていないOpenSSLライブラリと動的にリンクされている場合、SNIは利用できません。
互換性
- SNIサポートステータスはバージョン0.8.21と0.7.62から"-V"スイッチを使って表示されます。
-
listen ディレクティブの
ssl
パラメータはバージョン0.7.14からサポートされています。0.8.21以前は、default
パラメータと一緒にのみ指定することができました。 - SNIはバージョン0.5.23からサポートされています。
- 共有SSLセッションキャッシュはバージョン0.5.6からサポートされています。
- バージョン 1.9.1以降: デフォルトのSSLプロトコルは TLSv1, TLSv1.1, と TLSv1.2 (OpenSSLライブラリがサポートしていれば)です。
- バージョン 0.7.65, 0.8.19 <s0>以降</s0>のデフォルトのSSLプロトコルは SSLv3, TLSv1, TLSv1.1, と TLSv1.2 (OpenSSLライブラリがサポートしていれば)です。
- バージョン0.7.64, 0.8.18 <s0>以前</s0>のデフォルトのSSLプロトコルはSSLv2, SSLv3 と TLSv1 です。
-
バージョン1.0.5 以降のデフォルトのSSL cipherは
HIGH:!aNULL:!MD5
です。 -
0.7.65, 0.8.20 以降のデフォルトのSSL cipherは
HIGH:!ADH:!MD5
です。 -
バージョン 0.8.19 から、デフォルトのSSL cipherは
ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM
です。 -
バージョン 0.7.64、0.8.18以降 : デフォルトのSSL cipherは、"
ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
" です。
written by Igor Sysoev edited by Brian Mercer |