nginx

HTTPS サーバの設定


english
русский

简体中文
עברית
日本語
türkçe

ニュース [en]
nginx について
ダウンロード [en]
セキュリティ情報 [en]
ドキュメント
faq
リンク [en]
[en]
サポート [en]

trac
wiki
twitter
nginx.com
This translation may be out of date. Check the English version for recent changes.
HTTPS サーバの最適化
SSL 連鎖証明書
単一の HTTP/HTTPS サーバ
名前ベースの HTTPS サーバ
複数サーバ名をもつ SSL 証明書
サーバ名指示(Server Name Indication – SNI)
Compatibility

HTTPS サーバを設定するには server ブロックで SSL プロトコルを有効にして、サーバ証明書ファイルと秘密鍵ファイルの場所を指定する必要があります:

server {
    listen               443;
    server_name          www.example.com;
    ssl                  on;
    ssl_certificate      www.example.com.crt;
    ssl_certificate_key  www.example.com.key;
    ssl_protocols        SSLv3 TLSv1;
    ssl_ciphers          HIGH:!ADH:!MD5;
    ...
}

サーバ証明書とはドメインの所有者情報や、送信情報の暗号化に必要な公開鍵を含む電子証明書です。そのサーバに接続するすべてのクライアントに送られます。秘密鍵はサーバ証明書に含まれる公開鍵で暗号化された情報を復号するために必要な鍵で、秘匿する必要が有ります。アクセスを制限したファイルに保存するようにしてください。ただし、nginx のマスタープロセスからは読めるようにする必要があります。もうひとつの方法として、秘密鍵は証明書と同じファイルに保存することもできます:

    ssl_certificate      www.example.com.cert;
    ssl_certificate_key  www.example.com.cert;

この場合もファイルのアクセス権は制限するようにします。証明書と秘密鍵がひとつのファイルに保存されていても、証明書だけがクライアントに送られます。

SSL プロトコルの強力なバージョンと暗号に接続を制限するには、ディレクティブ ssl_protocolsssl_ciphers を使用します。バージョン 0.8.20 以降、nginx は ssl_protocols SSLv3 TLSv1ssl_ciphers HIGH:!ADH:!MD5 をデフォルトとして使用しているので、これより古い nginx のバージョンでのみ設定してください。

HTTPS サーバの最適化

SSL の工程は CPU リソースを余計に消費します。マルチプロセッサシステムでは(利用できる CPU コアの数よりも大きい数の)複数のワーカープロセスを走らせるといいでしょう。最も CPU に負荷がかかる工程は SSL ハンドシェイクです。クライアント毎のこの工程数を最小化するには2つの方法があります。最初の方法はキープアライブ接続を有効にして、ひとつの接続経由で複数のリクエストを送るようにする方法です。二つ目の方法は SSL セッションパラメータを再利用して、並行かつ順次接続のための SSL ハンドシェイクを避ける方法です。セッションはワーカー間で共有される SSL セッションキャッシュに保持され、ssl_session_cache ディレクティブで設定されています。1メガバイトのキャッシュには約4000のセッションが含まれます。キャッシュのデフォルトタイムアウトは5分です。この値は ssl_session_timeout ディレクティブを使用して増やすことができます。次の例は10Mの共有セッションキャッシュをもったクアッドコアシステムに最適化された設定例です:

worker_processes  4;

http {
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;

    server {
        listen               443;
        server_name          www.example.com;
        keepalive_timeout    70;

        ssl                  on;
        ssl_certificate      www.example.com.crt;
        ssl_certificate_key  www.example.com.key;
        ssl_protocols        SSLv3 TLSv1;
        ssl_ciphers          HIGH:!ADH:!MD5;
        ...

SSL 連鎖証明書

ブラウザによっては有名な認証局によって署名された証明書にエラーをだすことがあります。その一方でその証明書を他のブラウザでは問題なく受け入れることもあります。これは発行している認証局が、有名で信用されている認証局の認証基盤には含まれない特定のブラウザで配布されている中間証明書を使ったサーバ証明書に署名しているからです。このケースでは、認証局は署名されたサーバ証明書に連結されているはずの連鎖証明書のバンドルを提供しています。サーバ証明書は、かならず結合されたファイル内の連鎖証明書に存在している必要があります:

$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

この結合されたファイルを ssl_certificate ディレクティブで使われるようにします:

server {
    listen               443;
    server_name          www.example.com;
    ssl                  on;
    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
...
Certificate chain
 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
...

この例では、www.GoDaddy.com サーバ証明書 #0 の対象 (“s”) はそれ自身が証明書 #1 の対象である発行者 (“i”) によって署名されています。そして、証明書 #1はそれ自身が証明書 #2 の対象である発行者によって署名され、証明書 #2 は有名な発行者である ValiCert, Inc. によって署名されていて、ValiCert, Inc. の証明書はブラウザに組み込まれている証明書ベースに保持されています(こうして連鎖します)。

もし証明書バンドルを追加していなければ、サーバ証明書 #0 しか見れません。

単一の HTTP/HTTPS サーバ

最初の段階から HTTP と HTTPS プロトコル用にサーバを分けて設定するのは優れた実践です。現時点では両者の機能性としては等しいかもしれませんが、将来的に大きな変更があるかもしれず、統合されたサーバの使用が問題になるかもしれません。とはいえ、HTTP と HTTPS のサーバが等しく、将来のことを考えたくないのなら、ディレクティブ ssl on を削除して *:443 ポートに ssl パラメータを追加することによって 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.8.21 以前では、nginx は default パラメータで待ち受けているソケットに ssl パラメータをセットすることしかできませんでした:
listen  443  default  ssl;

名前ベースの HTTPS サーバ

単一の IP アドレスを2つ以上の HTTPS サーバで待ち受けるように設定するとよく発生する問題があります:

server {
    listen           443;
    server_name      www.example.com;
    ssl              on;
    ssl_certificate  www.example.com.crt;
    ...
}

server {
    listen           443;
    server_name      www.example.org;
    ssl              on;
    ssl_certificate  www.example.org.crt;
    ...
}

この設定では、ブラウザはリクエストされたサーバ名に関わらずデフォルトサーバ、すなわちここでは www.example.com の証明書を受信します。これは SSL プロトコルの作用によるものです。この SSL 接続はブラウザが HTTP リクエストを送る前に確立されるので、nginx にはリクエストされたサーバ名は分かりません。したがって、デフォルトサーバの証明書を送ることしかできません。

この問題を解決するもっとも古くてもっとも堅実な方法は、各 HTTPS サーバに別個の IP アドレスを割り当てることです:

server {
    listen           192.168.1.1:443;
    server_name      www.example.com;
    ssl              on;
    ssl_certificate  www.example.com.crt;
    ...
}

server {
    listen           192.168.1.2:443;
    server_name      www.example.org;
    ssl              on;
    ssl_certificate  www.example.org.crt;
    ...
}

複数サーバ名をもつ SSL 証明書

単一の IP アドレスを複数の HTTPS サーバ間で共有する方法は他にもありますが、どれも欠点があります。ひとつは、SubjectAltName フィールドに複数サーバ名(例えば、www.example.comwww.example.org)をもつ単一の証明書を使用する方法です。しかし、SubjectAltName の長さには制限があります。

もうひとつの方法は、例えば *.example.org のようにワイルドカード名を持った証明書を使用する方法です。この証明書は www.example.org にマッチしますが example.orgwww.sub.example.org にはマッチしません。以上の二つの方法は組み合わせることもできます。証明書には、例えば example.org*.example.org のように SubjectAltName フィールドに完全一致名とワイルドカード名を含ませることができます。

すべてのサーバでひとつのメモリーコピーを継承するためには、複数サーバ名を持つ証明書ファイルとその秘密鍵ファイルを設定の http レベルに置くとよいでしょう:

ssl_certificate      common.crt;
ssl_certificate_key  common.key;

server {
    listen           443;
    server_name      www.example.com;
    ssl              on;
    ...
}

server {
    listen           443;
    server_name      www.example.org;
    ssl              on;
    ...
}

サーバ名指示(Server Name Indication – SNI)

単一の IP アドレス上で複数の HTTPS サーバを動かすときのさらに包括的な解決方法として TLSv1.1 Server Name Indication extension(サーバ名指示拡張) (SNI, RFC3546) があります。これは、ブラウザが SSL ハンドシェイクの間にリクエストされたサーバ名を渡せるようにするもので、それによりサーバはその接続でどの証明書を使用するべきかが分かります。しかし、SNI は限られたブラウザしかサポートしていません。現時点では次のブラウザのバージョン以降のものがサポートされています:

  • Opera 8.0
  • MSIE 7.0 (Windows Vista 以降のみ)
  • Firefox 2.0 および Mozilla Platform rv:1.8.1 を使用している他のブラウザ
  • Safari 3.2.1 (Windows バージョンでは Vista 以降)
  • Chrome (Windows バージョンでは Vista 以降)

nginx で SNI を使用するためには、nginx バイナリがビルドされたときの OpenSSL ライブラリとランタイムで動的にリンクされるライブラリの両方でサポートされていることが必要です。OpenSSL は設定オプション “--enable-tlsext”. でビルドされていれば、バージョン 0.9.8f 以降で SNI をサポートしています。OpenSSL 0.9.8j 以降ではこのオプションはデフォルトで有効になっています。nginx が SNI サポート付きでビルドされていれば、“-V” スイッチとともに起動すると nginx が次のように表示します:

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

しかし、SNI が有効になっている nginx が SNI サポート無しの OpenSSL ライブラリに動的にリンクされている場合、nginx は次の警告を表示します:

nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available

Compatibility

  • “-V” スイッチでの SNI サポートステータス表示は 0.8.21 以降と 0.7.62 でサポートされています。
  • listen ディレクティブの ssl パラメータは 0.7.14 以降からサポートされています。
  • SNI は 0.5.32 以降からサポートされています。
  • 共有 SSL セッションキャッシュは 0.5.6 以降からサポートされています。

  • バージョン 0.7.65 と 0.8.19 以降のデフォルトの SSL プロトコルは SSLv3 と TLSv1 です。
  • バージョン 0.7.64 と 0.8.18 以前のデフォルトの SSL プロトコルは SSLv2、SSLv3、TLSv1 です。

  • バージョン 0.7.65 と 0.8.20 以降のデフォルトの SSL 暗号は HIGH:!ADH:!MD5 です。
  • バージョン 0.8.19 のデフォルトの SSL 暗号は ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM です。
  • バージョン 0.7.64 と 0.8.18 以前のデフォルトの SSL 暗号は ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP です。

作成: Igor Sysoev
翻訳: DigitalCube Co. Ltd., wokamoto