HTTPSサーバの設定

HTTPSサーバの最適化
SSL 証明書チェーン
単独のHTTP/HTTPSサーバ
名前ベースのHTTPSサーバ
     幾つかの名前を持つSSL証明書
     Server Name Indication
互換性

HTTPSサーバを設定するには、ssl パラメータがserverブロック内のlistening sockets上で有効にされる必要があり、server certificateprivate 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_protocolsssl_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.comwww.example.org、がSubjectAltName 証明フィールドにある証明書を使うことです。しかしながら、SubjectAltName フィールドの長さには制限があります。

他の方法は、ワイルドカード名、例えば*.example.org証明書を使うことです。ワイルドカード証明書は特定のドメインの全てのサブドメインを保障します。しかしトップレベルのみです。この証明書はwww.example.orgに合致しますが、example.orgwww.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から "-enable-tlsext" の構成でビルドした時にSNIをサポートします。OpenSSL 0.9.8j からデフォルトでこのオプションは有効です。nginxがSNIサポートでビルドされた場合、nginxは"-V"スイッチを付けて実行した時にこれを表示します。

$ nginx -V
...
TLS SNI support enabled
...

しかしながら、もしSNIが有効になったNGINXがSNIをサポートサポートしていないOpenSSLに動的にリンクされた場合、NGINXは警告を表示します:

nginxがSNIサポートでビルドされたが、tlsextサポートしていないOpenSSLライブラリと動的にリンクされている場合、SNIは利用できません。

互換性

written by Igor Sysoev
edited by Brian Mercer
TOP
inserted by FC2 system