nginx での安全な SSL 設定 (Android 4.4.2 対応)

タイトルの通り、 nginx で SSL を設定する際、どのようにすればできるだけ安全に Android 4.4.2 に対応できるのかという話である。 記事の作成日時 (2017-05-20) に注意して参考にしてね。

結果

        
## based on https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.11.8&openssl=1.0.2k&hsts=no&profile=modern (2017-05-20).
    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /path/to/dhparam.pem;

    # modern configuration. tweak to your needs.
    #ssl_protocols TLSv1.2;
    #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    # For Android 4.4.2: modern + protocol TLSv1 + ciphers `ECDHE-RSA-AES128-SHA:!DSS`
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

      
結果 (server ディレクティブ内等で使う)

Android 4.4.2 への対応は、 TLSv1ECDHE-RSA-AES128-SHA があれば必要十分のようである。

Qualys SSL Labs でのテスト、結果は A ランク
A ランクになった

TLSv1.1 は正直必要ない気もする (TLS 1.2 も TLS 1.0 も使えず TLS 1.1 だけ使えるという環境も妙である)が、まああった方が自然だし TLS 1.0 よりは安全だろうということで追加した。 !DSS も正直意味や意義がよくわからなかったが、後述のページで "Intermediate" 設定にすると ssl_ciphers 末尾に出現するので、 "Modern" での推奨以外の設定を追加するならこれも念のためあった方が良いだろうと考えて追加した。 正直なくてもいいと思う。 少なくとも、なくても動く。

つくりかた

  • Generate Mozilla Security Recommended Web Server Configuration Files へ行き、項目を適切に選択する。
    • サーバは(今回の私の場合は) Nginx
    • プロファイル(対象環境)は Modern
    • サーババージョンと OpenSSL バージョンはそのまま入力 (補完にないバージョンかもしれないが、とりあえずスルーして本当のバージョンを入れた)
    • HSTS は本当は有効化した方が良いのだろうが、私はサーバの設定にミスした場合など万が一のとき HTTP を使いたいかもしれないと考え、有効化していない
  • 入力欄の下の方の "link" をクリックすれば、入力を URL のクエリに含めてくれる(このような感じで)。 サーバの設定ファイルに、コメントとしてこのリンクを入れておくのが良いだろう。
  • "Oldest compatible clients" の欄を見ると、 modern profile では Android 5.0 以上への対応になっているのが読み取れる。 一方、 intermediate profile では Android 2.3 以上と出る。 TLSv1 の追加は少し調べれば必要とわかるから良いとして、 ssl_ciphers で追加が必要な最小限の設定は、 modern と Intermediate での差分の先頭から順に、どれが必要か二分探索でもして試していけば良い。 結果として ECDHE-RSA-AES128-SHA が必要、かつこれひとつの追加で十分であることがわかった。
  • ssl_protocolsssl_ciphers にこれらを反映してやれば変更は完了だ。

以下、ぼやき

  • 本来であれば SSL Labs のテストで A+ 評価だったのに、 Android 4.4.2 対応のせいで A に落ちた。くやしい。

    2017-11-25 追記: 関係なかったっぽい。

  • HSTS を有効化すると、 SSL Labs で A+ 評価をとれる。

  • 私が使っている端末が、もう4年目になる Android 4.4.2 であるが、本当はこんなものを使いたくない。 が、コミケとかおたくショッピングに金を注ぎ込んでいるため買い替える金がなく、ずっと使い続ける破目になっている。

  • Firefox や Chrome 等のまともなブラウザであれば、独自に実装されているようで、プラットフォームが古くとも強い暗号設定を使うことができる。 問題なのは、 Android デフォルトの通信機能を使うらしいアプリ群だ。

    たとえば Redmine のアプリで、サーバの暗号化設定が安全すぎるとログインできない。 他にも GNU Social / Mastodon に対応している twitter クライアントなどは、古い暗号化形式でも受け入れてくれるサーバのユーザのプロフィールは見られるが、安全すぎる設定のサーバ上のユーザのプロフィールは見ることができない。

    誰が悪いかと言われると、まあいつまでも古い端末を使い続ける私なのだが、それでもやはり OS アップデートを停滞させたり早期に停止しがちなキャリアのサポートにモヤモヤするのも事実である。 せめて Android 5 に上げてくれていればなぁ……

  • 金が欲しい。