NginxでSSL (その勘所)

SSL証明書発行まではApacheでSSL(その勘所)と全く同じ。SSLs.comでの証明書の種類選択もApache2用で良い。
と、いうか証明書の種類にNginxという選択肢がない(2015年12月現在)

SSLサーバ証明書

例えばSSLs.comで購入するとSSL証明書はComodoやGeotrustからメールで送付されて来る。そのメールにRapidSSLの場合は本文に、PositiveSSLの場合は本文(Web Server CERTIFICATE以下)と添付ファイル(ZIPファイル中の申請したホスト名orドメイン名.csrという名前のファイル)の両方にSSLサーバー証明書があるので/usr/local/etc/nginx/ssl/example/にserver.crtというファイル名で保存。(path/ファイル名は任意)

SSLサーバー証明書の例

-----BEGIN CERTIFICATE-----
MIIpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
(途中略)
T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDI
-----END CERTIFICATE-----

また、RapidSSLの場合はメール本文の(INTERMEDIATE CA:以下)に、PositiveSSLの場合は添付ファイルの(ZIPファイル中のPositiveSSLCA2.crtという名前のファイル)で中間認証局証明書が付くのでそれをserver.crtに追記。

-----BEGIN CERTIFICATE-----
MIIpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
(先に保存したserver.crt)
aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDI
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
(付属の証明書)
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----

証明書は2つ3つ4つマージしなければならないかもしれないが、一番上が自分のサーバの証明書で下に並ぶほどルート証明書に近くなる。ただし、調子に乗ってルート証明書まで追加しない。(ルート証明書はブラウザに入っている筈)

OCSP Staplingを有効にする場合は以下も(推奨)

中間認証局証明書とルート証明書を上と同様にテキストファイルに書いてtrusted.crtという名前(任意)で保存。
こちらはサーバ証明書が無くて替わりに最後にルート証明書が入るという点が違う。

DH Groupを作成する

% openssl dhparam -out dhparams.pem 2048
% mv dhparams.pem /usr/local/etc/nginx/ssl/example/

Nginxの設定

Nginxのvirtual host設定ファイルを編集。
SSLのセキュリティを考えると使えるプロトコルは以下の様に変更するのがオススメ。

server {
        listen 80;
        listen 443 default_server ssl;
        server_name www.example.com;

        ssl_protocols           TLSv1.2 TLSv1.1 TLSv1;
        ssl_certificate         /usr/local/etc/nginx/ssl/example/server.crt
        ssl_certificate_key     /usr/local/etc/nginx/ssl/example/server.key;
        ssl_dhparam             /usr/local/etc/nginx/ssl/example/dhparams.pem;
#        ssl_ciphers             HIGH:!3DES:!aNULL:!DH:!DSS:!PSK:!SRP; #昔はこれで良かった
        ssl_ciphers             EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; #HTTP/2時代はこれ
        ssl_prefer_server_ciphers   on;  #サーバ側で指定する暗号スイート(上の行)を使わせる指定
        ssl_session_cache       shared:SSL:10m;
        ssl_session_timeout     10m;

        ssl_stapling            on;
        ssl_stapling_verify     on;
        ssl_trusted_certificate /usr/local/etc/nginx/ssl/example/trusted.crt;
        resolver                DNSのIPアドレス;

        #add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";

        gzip                    off;   #BREACH簡易対策
        root /usr/local/www/example;
        access_log /var/log/access-example.log;
        error_log /var/log/error-example.log;
        ホニャララ
        }
} 

暗号強度(暗号スイート)の書き方については正直結構難く、どうしたいというポリシーもサイトや運営者によって違う筈。
書き方はApacheと同じ。
ssl_ciphersの指定は上の設定ファイル例をそのまま使用すると古いブラウザで問題が発生する場合があるので注意。
ブラウザ互換性と安全性の両方取りをしたいなら SSLCipherSuite HIGH:AES128:!aNULL:!DH:!DSS:!PSK:!SRP; あたりが個人的なお勧め設定。(だけど最近は指定順序も重要になっているのでHIGHをいきなり先頭で指定するのはやめた方が良いかも。)
最近はssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; がオススメです。特にHTTP/2では。

以上でPoodle, FREAK, Heartbleed, Logjam Attackなどの脆弱性に対応している。

確認

% openssl s_client -host www.example.com -port 443 -status

コマンド実行。

OCSP response: 
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: 90AF6A3A945A0BD890EA125673DF43B43A28DAE7
    Produced At: Dec 27 12:03:25 2015 GMT

最初の方にOCSP responseがある。
OCSP Response Statusが successful になっていることを確認。

SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: 59AE99979CA4D7A88E52B9D0FF8F22DAE3ECBBD1F28E12345368E04384E13721
    Session-ID-ctx: 
    Master-Key: FB228153985D55F17EE64884022D38737D53434EC11748B0F8B28DCDD2ED7180298B24C5AAD30F29D25D8BEFD394F443
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 600 (seconds)
    TLS session ticket:
    0000 - 22 28 3b 4f 38 28 dc 61-2d 0b a2 97 7e 6a aa 21   .(;O8(.a-...~j.!
    0010 - c2 d3 6f fd 0e 31 9f 30-4b fd 93 9a 45 20 57 21   ..o..1.0K...E W!
    0020 - 59 06 c7 39 dd 69 78 af-69 ea 38 14 c4 aa 4b f5   Y..9.ix.i.8...K.
    0030 - f1 a9 76 ab a1 47 5b 24-24 19 90 4a a3 54 9e af   ..v..G[$$..J.T..
    0040 - 32 3e e0 31 76 08 9e 4c-2f a2 46 ac 7b 94 15 99   2>.1v..L/.F.{...
    0050 - b8 60 c6 18 16 1f 7e 2e-0b 0b 74 67 89 60 75 60   .`....~...tg.`u`
    0060 - 0e 05 9a fc 3e 27 bf b1-f7 41 86 af 72 8a de 33   ....>'...A..q..3
    0070 - c4 10 1d 1e 10 94 bb 21-ee 53 97 67 d7 1f a1 03   .......!.S.g....
    0080 - ee 2a b5 e0 60 ee ae 08-c7 c3 0a 4f 72 88 54 61   .*..`......Oq.Ta
    0090 - f9 bd af a3 b7 4c b7 99-4e 63 8c 57 7a 34 a8 5c   .....L..Nc.Wz4.\
    00a0 - 5c 52 a5 75 e3 d3 38 02-56 76 f6 21 70 0f 73 65   \Q.u..8.Vv.!p.se

一番最後の方にSSL-Sessionがある。
ProtocolがTLSv1.2, TLSv1.1, TLSv1のいずれかであることを確認。
Cipherが意図したものであることを確認。
Session-IDが表示されていることを確認。
TLS session ticketが表示されていることを確認。

Apache用と同じくQUALYS SSL LABS(英語)等で確認すると、何かおかしな点があれば親切に指摘してくれる。