すこしまえに、CentOS7 の ndjbdns を使うと一部機能が使えない、という話を書いた。
今度は nginx の同様な話。
CentOS 7 では、nginx の yum パッケージがあるのだけど、これで http2 を使おうと思っても使えない。
じゃぁ、nginx を作り直せばいいんだな…と思って自分で構築しても、やっぱり使えない。
nginx はエラーを出さないが、ただ http2 が使えない。
エラーが出ないので原因に気付くのに時間がかかった。
結論から言えば、CentOS 7 の OpenSSL のバージョンが古い
1.0.1i 以降の OpenSSL がないと http2 を使えないのだけど、CentOS 7 のバージョンは 1.0.1e だ。
ちなみに、この日記執筆時点の最新版は 1.0.2j 。
nginx のソースと、OpenSSL 1.0.2j のソースを /usr/local/src に置き、nginx の configure に以下を加える。
--with-openssl=/usr/local/src/openssl-1.0.2j/
--with-http_ssl_module
--with-http_v2_module
これで CentOS 7 の nginx でも http2 通信ができるようになる。
2018.11.16 追記
8月に、WEBで使用される新しい暗号技術、TLS 1.3 の策定が完了、公開されました。
これに伴い、各種ブラウザでも TLS 1.3 の実装が行われています。
この記事は、TLS 1.2 時代のもので、次第に古くなる可能性があります。
とはいえ、古いブラウザのために TLS 1.2 はまだ残されますし、現状では下の設定でもセキュリティ評価は A+ (最高ランク)になります。
追記時点での、OpenSSL の最新版は 1.1.1 だ。
これを使えば、自動的に TLS 1.3 に対応し、使用できる場合は使用される。
その際の設定などは、この記事の設定のままでいいはずだ。
(まだ試していない。)
さて、今まで http だった当サイトも、https に対応した。
SSL の対応状況を調べてくれる、Qualys SSL LABS でチェックしながら対応を進めた。
このページ、最高評価は A+ だ。
そして、このページで A+ を取るための方法、と書かれたページはたくさんある。
でも、それらのページを参考にしても A+ は取れない。
SSL に進展があったり脆弱性が見つかったりすると、チェック内容は変更されるためだ。
まぁ、A+ を取ることが正義ではないので、A- くらいとれていれば十分じゃないかな、と思う。
でも、例えば「設定が間違えていてアクセスできないブラウザがある」とかだと残念だ。
チェックはしておいた方がいいだろう。
そして、設定の中で一番重要になるのが、ssl_ciphers の設定だ。
これは OpenSSL に指示する、使っても良い暗号化形式のリストだ。
クライアントは、このリストの先頭から順に、自分が使える暗号形式を探す。見つけられればその形式でアクセスを行う。
どの暗号形式を許可するか?
これによって、安全性も大きく左右されるし、設定を間違えるとアクセスできないブラウザも出てくる。
目安としては、先に書いた SSL LABS のチェックを作っている人たちが、チェック項目の意味を解説しているページがある。
このページは、暗号に脆弱性が見つかる、などの状況変化により書き換えられる。
なので、以下の内容は記事執筆時点 (2016.10.22) のものだとお断りしておくのだけど、このようなことが書いてある。
・公開暗号鍵を 2048bit にすること
・SSL v2 / v3 には脆弱性があるから使わないこと。
・TLS v1.0 はあまり使用すべきではないが、まだ必要。
・TLS v1.1 と v1.2 は問題ないが、できることなら v1.2 を使うこと。
他にもいろいろあるのだけど、ssl_ciphers の設定に関係するのは以下のようなものだ。
・匿名 ADH は使用しない。
・NULL 暗号は使用しない。
・56bit 以下の弱い共有暗号鍵を使用しない。
・RC4 は安全ではない。
・3DES は遅く、弱い。
・出発点としては RSA および ECDSA を使うようにするとよい。
さて、具体的に ssl_ciphers をどのように設定すべきだろう。
そもそも、ssl_ciphers は「どうやれば」設定できるのだろう?
構築時に OpenSSL のソースを組み込んだことを思い出そう。
ssl_ciphers は、OpenSSL が解釈できる文字列で指示を与える。
指示にあるように「RSA および ECDSA を使う」のであれば
RSA ECDSA
と併記すれば良い。
試しに、openssl コマンドで、この指定を試してみよう。
openssl ciphers -v 'RSA ECDSA'
と併記すると、これらに関係する暗号の一覧が示される。
中には RC4 という文字列を含む暗号名も見られる。
これは「安全ではない」と示されているので、除外したい。
この場合は
RSA ECDSA !RC4
のように指定する。! は「除外する」という指定だ。
56bit 以下の弱い共有暗号鍵を使用しない、という指示もある。
実は、これは HIGH という表記で「128bit 以上」だけを選び出せる。
HIGH
この指定を行えば、RC4 は最初から除外されている。
実際には、ここを出発点とするといいだろう。
HIGH の一覧を出してみると、暗号名の後ろに Au=None と書かれているものがある。
「匿名のADHを使用しない」と指示にあるが、Au=None というのが「匿名」を意味している。
Au は Authorize 、認証の意味で、これが None 、つまり「認証しない」という、匿名を意味している。
これは、Au が NULL である、という表現をする。指示の際は aNULL 。
先ほどの指示からこれを除外しよう。
HIGH !aNULL
これだけで、とりあえず目的は達成できる。
他の設定も適切なら、A+ 評価を得られる。
でも、評価ページの詳細を見ると、いくつかのクライアントでアクセスができないことがわかる。
解消できるものならば、解消したほうがいいだろう。
まずは、次の2つだ。
Chrome 49 / XP SP3
Firefox 47 / Win7
どちらも同じエラーを出して、接続できていない。
SSL で使う暗号には、暗号利用モードと呼ばれる概念がある。
古い https 通信では CBC と呼ばれるモードを使う。
この方法は、直前の暗号文を鍵の一つとして使う。つまり、先頭から順番にしか暗号化できない。
でも、http2 では、1つのコネクションで複数のデータリクエストを並列に受付られる。
ということは、並列に暗号化を行う必要がある。CBC ではない方法を使わないといけない。
しかし、https では、クライアントが使用できる形式のうち、サーバーから渡されたリストの先頭に近いものを優先して使う決まりになっている。
サーバーが、クライアントが使える暗号形式の中で、CBC のものを先に渡してしまったために、それを利用しようとして http2 での通信ができなくなった、というのがアクセスできなかった理由だ。
評価サイトで、クライアント名の部分のリンクを辿ると、そのクライアントの詳細な性能が出てくる。
使用できる暗号化の形式もわかる。
とりあえず、上記二つのクライアントでは CBC 以外として AESGCM の形式を理解できる。
そこで、これらを優先して渡すことにする。
AESGCM HIGH !aNULL
これでいい。
いや、まだだ。
IE 8 / XP がアクセスできていない。
えー、もう XP はサポート範囲外だし、IE 8 なんて誰も使ってないからいいでしょ。…とも思う。
まぁ、無視してもいいと思うのだけど、乗り掛かった舟だから対応してみよう。
こちらも、使用できる暗号形式を見る。
うわ…さすがに古いので、セキュリティ的に問題がある暗号形式ばかりだ。
実用上、使えるものが 3DES しかない。
3DES は「遅く、弱い」とされているのだけど、脆弱性があるわけではないので、対応してみよう。
間違えて他のクライアントが使うと困るので、リストの最後に追加する。
AESGCM HIGH !aNULL 3DES
これでもまだ、対応できていないクライアントが2つある。
IE 6 / XP
Java 6u45
この2つへの対応を行うと、セキュリティ上問題が生じてしまうので、残念ながら切り捨てよう。
IE 6 / XP は、SSL には対応しているが、上位規格である TLS には対応していない。
SSL には脆弱性が見つかっているため、使用してはならない。
Java 6u45 は、公開暗号鍵として 1024bit までしか受け付けない。
1024bit では強度に問題があるため、2048bit を設定することが推奨されている。
とりあえず、話としてはこれで終わりなのだけど、この設定をしても妥当ではない場合もあり得るので説明しておこう。
OpenSSL は、バージョンによって、もしくはコンパイル時のオプションによって、使用できる暗号が異なる。
ここに書いた内容は、冒頭で書いたように 1.0.2j を前提としている。
SSL LABS で、各ブラウザが利用できると表示される暗号名は、OpenSSL のものとは違う。
でも、最後に16進で暗号を示す番号が書かれている。
OpenSSL でも、-v ではなく、-V (大文字)オプションを使うとこの番号を表示できる。
番号を頼りに、適切な暗号形式を探すといいだろう。
そしてこれが一番大切なことだけど、最初に書いた通り、時代と共に適切な暗号は変化する。
もしここに書いてある内容で十分でなかったら、その時点での推奨される方法を SSL LAB のブログで調べるといいだろう。
そして、除外すべきものを除外する。HIGH の指定を使っているので、おそらく「追加すべき」はあまりないと思うが、必要なら追加する。
SSL LAB のページは、一度評価を行うと、しばらくはその結果をキャッシュしている。
そのため、こちらが設定を変化させて、確認しようとリロードしても、評価を行ってくれない。
これは、ページ左上にある「Clear cache」のリンクに飛べば、再評価してもらえる。
最後に、もう一度まとめておこう。
2016.10.22 時点での最良の ssl_ciphers 指定は
ssl_ciphers 'AESGCM HIGH !aNULL 3DES';
となる。
2016.10.25追記
SSL/TLS で使われる暗号について、わかりやすい説明をしているページを見つけた。
いろんなページを読んで理解して説明を試みたのだけど、長くなってしまうので書くのを辞めた部分。
専門的でわかりにくいかもしれないけど、なんとなく頭に入れてから設定を行うと、いろいろとわかってくると思う。
同じテーマの日記(最近の一覧)
関連ページ
別年同日の日記
申し訳ありませんが、現在意見投稿をできない状態にしています。 |