NginxでHTTPS : ゼロから始めてSSLの評価をA+にするまで Part 1

数年前、Webは全体的に暗号化されていませんでした。HTTPSはWebページの最も重要な部分だけのために確保されていました。暗号化が必要なのは大切なユーザデータだけで、Webページの公開される部分は暗号化せずに送ってもいいということで意見が一致していました。

しかし、今は状況違います。現在では、どんなWebトラフィックでも暗号化されていないのは良くないということが分かっているので、Webサイトを運営する誰もがコンテンツに関係なく強固なHTTPSを設定しなければなりません。

お恥ずかしい話ですが、私自身のWebサイトは2年近くも全くHTTPSをサポートしていませんでした1

Eric Mill今すぐ無料でHTTPSに切り替えようという素晴らしい記事が最終的に私に喝を入れてくれました。私は休暇中、HTTPSをセットアップしてQualys SSL ReportA+を獲得できるように設定を微調整することに時間を費やしました。

A+ score on juliansimioni.com

かなりの研究が必要でしたが、ほぼ最適な設定が決まったので、Nginx上でそれを実現した方法を共有したいと思います。実際の構成に加えて、安全な設定における全てのコンポーネントの動作と、なぜその設定が最適なのかについて説明します。

この記事はパート1です。ここでは基礎を紹介し、証明書をセットアップしていきます。

パート2では、Nginxの設定をもっと説明し、特にciphersuiteのセットアップについて見ていきます。

初期設定: 自己署名証明書を使用

HTTPSを有効にするだけなら要求されるものはほとんどありませんが、サーバに暗号化鍵と証明書ファイルを設定する必要があります。OpenSSLがインストールされたマシンであれば、両方とも素早く簡単に作成できます。

このような自己署名証明書は真の安全を保証するものではありませんが2、本物の証明書を生成する前に一度セットアップしてみたら、大まかなプロセスを理解できるでしょう。そうすれば、早い段階でできるだけ多くの問題を解決できるので、やってみる価値はあります。

自己署名証明書の生成に関しては既にあまりにも多くのチュートリアルがあるので、ここでは詳細を省きます。次のような簡単なコマンドで十分でしょう。

mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
openssl req -new -x509 -sha256 -newkey rsa:2048 -days 365 -nodes -out /etc/nginx/ssl/nginx.pem -keyout /etc/nginx/ssl/nginx.key

基本的なSSL3向けのNginxの設定部分も簡単です。以下の設定をnginxファイルに追加します。

server {

      # [...]

      listen 443 ssl;
      ssl_certificate      /etc/nginx/ssl/nginx.pem;
      ssl_certificate_key  /etc/nginx/ssl/nginx.key;

      # [...]
}

(上記のコードスニペットは両方とも前述のリンク先Linode認証ガイドからの応用です。最高のチュートリアルの1つです)

これで有効な証明書が用意できたので、Nginxを再起動すればサイトがHTTPS経由でロードされるようになります。ただ、証明書は自己署名なのでおそらく厄介な警告が出るでしょう。そこで、完全な証明書を使ってやってみる前に、重要な機能に関していくつか初期チェックを行います。

OpenSSLの最新バージョンを確認

OpenSSLライブラリは、ほとんどどこにでもあるSSLとTLSライブラリのようなもので、Nginxを含むほぼ全てのWebサーバで使用されています。OpenSSLのバージョンが古い場合、セキュリティの脆弱性がいくつもあるかもしれません。

中でも最悪なのは、もちろんHeartbleedです。Webサーバの秘密鍵を含むあらゆる種類のデータが漏えいしてしまう恐れがあります。Heartbleedは2014年4月に初めて公表されましたが、多くのWebサイトは脆弱なままです。そんなWebサイトにしてはいけません。

OpenSSLのWebサイトで最新の安定したバージョンを確認して、自分のサイトでその最新バージョンが使われているか確認してください。

$ openssl version
OpenSSL 1.0.1k 8 Jan 2015

2048ビットおよびSHA256の署名による証明書の作成を確認

自己署名証明書はコストやダウンタイムを発生させずに簡単に再生成できるので、この段階で証明書の設定の問題を解決しておく方がいいと思います。無料のStartSSLの証明書ですら取り消すのに3,000円近くかかるため、間違えると後でもっとコストと時間がかかります。

証明書を設定する際に最も重要なのが、どのハッシュアルゴリズムを使ってフィンガープリントを生成するかということです。つい最近まで、ほとんどの証明書はSHA1を使って署名されていました。しかしGoogleMicrosoftといった企業や多くの[セキュリティ研究者] (https://www.schneier.com/blog/archives/2012/10/when_will_we_se.html)が今や、SHA1の利用を速やかにやめるよう強く推奨しています。コンピュータの処理能力が進化するにつれて、SHA1は危険なレベルにまで安全性が下がってきています。今後新たに発行される証明書は、SHA1ではなくSHA256で署名されなければなりません。

現時点においては、SHA1に対する実際の攻撃が行われたという事例は報告されていません。しかしChromeやFirefoxでも早々に、SHA1で署名された証明書については警告またはエラーが出されるようになります。要するに、今後はSHA256以外のハッシュ関数で新しい証明書を生成してはいけないのです。

RSA暗号の鍵のサイズについても同様です。現在、RSAでは2048ビット鍵が最適4となっています。現在の環境は、十分にパワフルなコンピュータネットワークがあれば、1024ビットでの証明書でも解読できるレベルに達しています。そしてSHA1に対する対応と同じように、ブラウザ側はこれ以上1024ビット鍵が使われることを防ごうとしています。例えばMozillaは、2014年9月にリリースされたFirefox32では、信頼される証明書リストから1024ビットの認証局鍵を除きました

先ほど紹介したコマンドを使って自己署名証明書を生成すれば、SHA256と2048ビットRSA鍵に対応しているはずです。次のコマンドを使えば確認できます。

openssl x509 -in /etc/nginx/ssl/nginx.pem -text -noout | grep "Signature\|Public-Key"
# Should give the following output:
# Signature Algorithm: sha256WithRSAEncryption
# Public-Key: (2048 bit)
# Signature Algorithm: sha256WithRSAEncryption

(ServerFaultで見つけたこちらの回答を応用しました)

万が一、sha1WithRSAEncryption(1024 bit)という結果が出てきた場合は最初に戻ってもう一度正しい設定を確認し、再度証明書を生成してください。

コンテンツの混在に関する警告を確認

この段階では、たとえ初期リクエストがHTTPS経由になっていても、JavaScriptやCSS、画像といったWebサイト上のリソースはまだHTTP経由でロードされている可能性が非常に高くなっています。

Mixed content warning in Firefox

コンテンツの混在を示す警告の例(Firefox版)

これまでは、ログインページやフォームの送信といったWebサイトの重要な部分だけにHTTPSを使うだけで十分とみなされていましたが、今や状況は変わりました。現在のブラウザは、より危険性を増した様々なコンテンツの混在(つまり、JavaScriptとCSSファイルのこと)をブロックするようになりました。

これはユーザにとって、大変優れたセキュリティ面での利点となります。なぜならこうしたコンテンツが混在したファイルは、通信されている間に修正を加えられ、結果 深刻な被害をもたらす可能性があるからです。大切なユーザ情報が盗まれたり、システムにマルウェアをしかけられたり、といったことが起こりうるのです。

コンテンツの混在に対する警告を修正する方法は各Webサイトのコードによって様々ですが、たいていの場合リンクの頭をhttp://からhttps://に変更するような単純なものです。他のサーバからリソースをロードするようなリンクについても同様です。万が一サーバがHTTPSをまだサポートしていない場合、そのサーバからのリソースは完全に取り除くか、可能であれば自分でホストする必要があります。

どうしてもHTTPとHTTPS双方をサポートする必要がある場合、protocol-relative URLといった方法もありますが、お勧めできるものではありません。

実践:認証局署名の証明書利用

基本的な課題がクリアできたところで、ブラウザが信頼していると実際に認識できる証明書を生成してみましょう。この作業はいくつかの理由によってはちょっとした長さのプロセスになります。まずは事前に必要とされる事項を確認しましょう。

  1. 認証局(CA)のアカウント
  2. webmaster@yourdomain.com、または postmaster@yourdomain.com、またはドメインのDNSエントリにあるSOAレコードにリストされているメールアドレスのいずれか、へのアクセス
  3. 証明書リクエスト(CSR)ファイル

上記の1はおそらく、普通のWebページ用にアカウントを取得するよりは少し面倒な手続きとなるでしょうが、なんとかなるはずです。セキュリティ上の懸念を考慮しているので仕方がないことです。まだどの認証局を使うか決めていなければ、StartSSLが良いでしょう。機能も優れていますし無料です。有料サービスを選ぶならばVerisignComodoがあります。GoDaddyはお勧めできません

上記の2は、それぞれのDNSセットアップの状況に応じてやり方が大きく異なるので、ここでは詳細には触れません。DNSが適切に設定されていないと、DNSエントリに変更を反映するのに数時間かかることもありますので、すぐ作業に取り掛かってください。

しかし私のように、 FastMailで自分のドメインを使ってメールを管理している場合は、FastMailが既に全てのセットアップを行ってくれています。もしFastMailを使っていないのでしたら、実に素晴らしいサービスなのでぜひ使用することをお勧めします。

1と2のステップを完了したらCSRを作成できます。このファイルには、証明書を必要とするドメインやオプションなどの詳細が記述されています。認証局の中には、ブラウザで秘密鍵やCSRを生成する”手助け”をしてくれるものもあります。既に秘密鍵の生成は済んでいるので、認証局の手助けは断ります。セキュリティ違反となる恐れがあるため、必要ありません。

次のコマンドを使うと、優れたCSRが生成されます。

openssl req -new -sha256 -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/yourwebsite.com.csr

認証局のWebページにあるCSR用のフォームに生成した内容を貼り付けると、証明書が返送されます。返送された証明書は、/etc/nginx/ssl/yourwebsite.com.crtのような、自分のサーバ上の安全な場所に格納しておきましょう。

もしStartSSLを使うことになった場合は、この記事の上の方にリンクを貼ってあるErik Millのチュートリアルを参照してください。全ての手順を完璧に網羅してくれています。

自己署名証明書の時と同じように、最初に、認証局からした新しい鍵とCRTファイルをNginxに設定するだけで機能するはずです5。おめでとうございます! これであなたのWebサーバは有効な証明書を取得し、TLSを使えるようになりました。

もし今すぐWebサイトでSSL Labsのテストを実施したら、以下のような結果が表示されるでしょう。

freshly-minted-certificate-test

悪くはありませんが、Nginxのデフォルトの設定ではCの評価までしか獲得できません。これは、ぎりぎり合格といったレベルです。次回、A+の評価を得るためにはNginxにどのような設定が必要なのか見ていきましょう。お楽しみに!



  1. 私のサーバはその間ずっと、HTTPSやポート443へのリクエストに対してレスポンスを返すことさえしませんでした。 

  2. 本当に安全な通信を実現するには、次の3つが必要です。適正な機関からのメッセージであることを証明すること(認証)、対象とする受け手だけがメッセージの内容を読めるように難読化すること(暗号化)、送信中にメッセージが変更されなかったことを証明する方法(メッセージダイジェスト)です。自己署名証明書は何の認証もしていないので、ほとんど役に立ちません。TLSに関するWikipediaのページに、機能の概要が分かりやすく説明されています。 

  3. 私がSSLと言う場合に実際に指しているのはTLSです。SSLとTLSは、どちらも同じ歴史的背景を共有しています。TLSは新バージョンの名前であるというだけです。SSLのバージョンは全て、今では時代遅れになってしまいましたが、名前だけは残っているのです。 

  4. 4096ビット鍵は今のところ、認証局を除けば過剰な長さだと考えられているので、2048ビットが最適なサイズです。2048ビット鍵の安全性は1024ビット鍵の2倍ではなく、2の1024乗倍ということを思い出してください。ただし、処理速度は2倍遅くなります。当分の間は2048ビットで十分と言えるので、4096ビット鍵は、単に暗号化の処理を遅らせるだけです。 

  5. 最初に、おそらく(このような感じの)OCSPエラーを受け取るでしょう。これは数時間で解消します。オンライン証明書状態プロトコル(OCSP)は証明書が取り消しになっていないかを判定するシステムです。あなたの証明書は発行されたばかりなので、証明書がまだ有効かどうかを確認する情報はシステムにはありません。そのため、その情報を取得するには少し時間がかかります。次の記事でOSCPについてもっと詳しく学びます。