wiz.code

ApacheでSSL接続

SSLの昨今

一昔前では、WebサイトのSSL対応にはそこそこの費用がかかりました。

SSLには電子証明書が必要ですが、一度の取得で数万円。 電子証明書には有効期限があり、ほぼ同じ金額で更新していかなければなりません。 企業や商売をしているサイトであればさほど大きな額ではありませんが、個人サイトとなると結構な出費になります。

もうひとつSSL対応に必要なものが、IPアドレスです。 電子証明書とIPアドレスは「1対1」で対応します。 つまり、ひとつのIPアドレスに対して割り当てられる電子証明書はひとつだけ、ということです。 安価なレンタルサーバーでは、複数の契約者が同じIPアドレスを共有するため、独自ドメインによる電子証明書を利用できません。 SSLに対応するためには、契約者ごとに異なるIPアドレスが支給される高額なレンタルサーバーが必要です。

最近は通信を暗号化する目的に限定された格安の電子証明書が登場し、個人でも購入しやすくなりました。 また、SNIという技術により、一つのIPアドレスで複数の証明書が利用できるようになり、 IPアドレス共有型のレンタルサーバーでも、独自ドメインの証明書を利用できるサービスが登場してきています。

SSLの導入がリーズナブルになったことで、今やSSL対応のサイトを作ることはそれほどハードルの高いことではありません。 そこで、構築中のサーバーでもSSLで接続できるように準備を進めていきます。 最終的にはSNI対応が目標。

非対称鍵暗号

ここで簡単に非対称暗号の話をします。 すでに仕組みをご存知の方は、このあと「SSLの準備」まで読み飛ばして構いません。

暗号化には「共通鍵暗号」と「非対称鍵暗号」の2種類があります。

「共通鍵暗号」は、データを暗号化する処理と、元に戻すための処理(復号)に同じ鍵を使う暗号方式です。 「施錠する鍵」と「開錠する鍵」が同じなので「共通鍵」と呼ばれます。

この方式では、データを送る側と受け取る側が事前に鍵を共有する必要があります。 この鍵をネットワークに流してしまうと、鍵と暗号化したデータが傍受された場合、簡単に復号できてしまいます。 また不特定多数と通信するホームページのような形態では、鍵の交換自体が困難です。

一方、「非対称暗号鍵」では、暗号化に使う鍵と、復号する鍵が別々になります。 暗号化に使った鍵では復号することができません。 「施錠する鍵」と「開錠する鍵」が同じではない、つまり「対称になっていない」ので「非対称鍵」と呼ばれます。

暗号化に使う鍵は「公開鍵」と言い、データを送る側に公開します。 もう一方の復号に使う鍵は「秘密鍵」と言い、データを受け取る側だけが所持します。 データを送る側は公開鍵を使ってデータを暗号化します。 データを受け取る側は、自分だけが持っている秘密鍵を使ってデータを復号します。 これなら、例え公開鍵と暗号化したデータが傍受されても、秘密鍵がないので復号できません。

鍵を分けるなんてことがどうやってできるの?と疑問になりますね。

非対称暗号鍵(RSA暗号)は「2つの巨大な素数の積を素因数分解する困難性」を利用した暗号化方式です。 例えば「767」という数値があります。 これは、ある2つの素数を掛けたものです。 これ、解けますか?

答えは「13×59」です。 この計算は、根気よく続ければ解けますが、簡単に解く方法はまだ見つかっていません。

では、これではどうでしょう? 「550,809,484,319」(5508億0948万4319)。 これも2つの素数を掛けたものです。 この桁になると、コンピュータを使ってもそれなりの時間がかかるようになります。

ちなみに答えは「637,711」と「863,729」です。 これが「2つの巨大な素数の積を素因数分解する困難性」です。

ところが、2つの素数を知っていれば、それを掛け算して「550,809,484,319」を得るのは簡単です。 非対称暗号鍵は、元となる2つの素数を「秘密鍵(の材料)」、掛け算した結果を「公開鍵(の材料)」とし、さらにいくつかの理論を組み合わせて暗号化を行っています。

実際の暗号には600桁程度の超巨大な素数が使用されます。 これだけ巨大な素数の積を因数分解するには、スーパーコンピュータを用いても何十年もの時間が必要になります。 この理論(非対称鍵暗号)が電子証明書を使った暗号化通信、すなわちインターネットに流れる情報の保護の要です。

ですので、万が一「秘密鍵」が他人に知られてしまったら、データを復号されてしまいます。 秘密鍵が漏洩しても被害が広く及ばないように、また将来的にコンピュータの性能が向上して素因数分解にかかる時間が短くなってしまったときのために、 電子証明書には有効期限があり、定期的に更新しなければならない仕組みが取り入れられているのです。

より詳しく知りたい方は、「RSA暗号」や「非対称鍵暗号」で検索してみてください。 ここで覚えておいてほしい要点は次の3点です。

SSLの準備

Apacheにmod_sslを追加

SSLの導入に必要なものは、前述した「電子証明書」と、SSLで接続できるようにする「環境」です。 まずは「環境」の準備。 すなわち、ApacheでのSSL対応です。

ApacheでSSLを使う場合は「openssl」と「mod_ssl」が必要です。 (Windows版では、SSL対応でビルドしたバイナリが必要です。) OpenSSLはすでにインストール済みです。 mod_ssl も yum で入手することができるようなので、インストールします。

mod_sslをインストール
# yum install mod_ssl

Apacheはひとまずここまで。 先に電子証明書を作ります。

秘密鍵の生成

ディレクトリの作成と移動

電子証明書の作成過程で、いくつかファイルが生成されるので、ユーザーのホームディレクトリに「ssl」というディレクトリを作って、そこに生成します。 ディレクトリはmkdirコマンドで作成します。 作成したら、そのディレクトリに移動しておきます。 (実際には秘密鍵を保護するため、外部や一般ユーザーからはアクセスできないディレクトリに作成することをお勧めします。)

# mkdir ssl
# cd ssl

はじめに、電子証明書の「秘密鍵」を作ります。 秘密鍵は「openssl」コマンドで生成します。 このコマンドに与えるパラメータは3つ。

genrsa
RSA(非対称暗号アルゴリズム)の秘密鍵生成を指示
2048
秘密鍵の強度を示すビット数(最近は1024bitではなく、2048bit以上が推奨されています)

出力先のファイル名はなんでもかまいません。 ここでは「wiz-code.private.key」とします。 コマンドのあとに「> (ファイル名)」とすると、コマンドの出力がそのままファイルに書き込まれます。

秘密鍵を生成
# openssl genrsa 2048 > wiz-code.private.key

生成された秘密鍵は絶対に外部に流出させてはいけません。 これは、閲覧者から受け取った暗号化されたデータを復号するためのものです。 取り扱いには充分に気を付けてください。

署名要求の作成

電子証明書を発行するための署名要求「CSR」を生成します。 署名要求とは、認証機関(VeriSignやGlobal Sign等)で証明書を発行してもらうための申請書みたいなものです。

署名要求を作成するには、OpenSSLコマンドに次のパラメータを指定します。

req
署名要求の処理を指示
-new
新しく作成することを指示
-key (Key File)
使用する秘密鍵を指定

出力されるファイルは「wiz-code.private.csr」としておきます。

署名要求の生成
# openssl req -new -key wiz-code.private.key > wiz-code.private.csr

このコマンドでは、実行後に署名要求の内容を記入します。

Country Name
国名。英字2文字、日本であればJPを指定
State or Province Name
都道府県
Locality Name
区市町村
Organization Name
組織名
Organizational Unit Name
部署・部門名
Common Name
SSLを使用するサイトのホスト名【重要】
Mail Address
メールアドレス

「Common Name」は特に重要です。 ここに記入したホスト名が、URLのホスト名(https://******/ の *****部分)として使用されます。 ここを間違えたまま申請してしまうと、発行費用が無駄になってしまいます。

その後、「A challenge password」が要求されます。 これは、証明書を破棄するときに使用するパスワードで、空欄でも構いません。 続く「An optional company Name」は、別の組織名・会社名などを記入する欄です。 なければこちらも空欄で構いません。

以上で、署名要求「wiz-code.private.csr」が作成されました。

証明書に署名

最後に、署名要求に署名して、電子証明書を発行します。 本来であれば、認証機関に署名要求を提出して、署名と証明書発行を行ってもらうのですが、そこに「費用」が発生します。 ここでは費用をかけずに自分自身が認証機関となって「自己署名」で証明書を発行します。 費用は掛かりませんが、認証機関を通していないので、証明書は信頼されません。 ブラウザでは、証明書の発行元が信頼できる認証機関でない場合、警告を発したり、サイトに接続できないようになっていますので、公開サーバーで使用する際は注意が必要です。

署名要求に署名するには、OpenSSLに次のパラメータを指定します。

x509
x509形式の証明書を作成することを指示
-req
署名要求の処理を指示
-days
証明書の有効期間日数を指示
-signkey (Private Key)
使用する秘密鍵を指定
-in (CSR File)
署名要求ファイルを指定
-out (Output File)
出力先を指定

出力されるファイルは「wiz-code.private.crt」、有効期間は365日としておきます。

署名要求に自己署名
# openssl x509 -req -days 365 -signkey wiz-code.private.key -in wiz-code.private.csr -out wiz-code.private.crt

これで証明書(自己署名型)が発行されました。 署名要求(wiz-code.private.csr)は今後使用しませんので、破棄して構いません。 秘密鍵(wiz-code.private.key)と証明書(wiz-code.private.crt)のみ使用します。

生成した電子証明書

SSLディレクトリを開いて、証明書をView Fileで開くと、署名要求に記入した内容や有効期限などがちゃんと設定されていることが分かります。

Apacheに証明書を割り当てる

秘密鍵と証明書をApacheに割り当てます。 秘密鍵は/etc/pki/tls/private/ディレクトリに、証明書は/etc/pki/tls/certs/ディレクトリにそれぞれコピーします。

# cp wiz-code.private.key /etc/pki/tls/private/
# cp wiz-code.private.crt /etc/pki/tls/certs/

次に、Apacheのssl.confを書き換えます。

ssl.confの書き換え
# vi /etc/httpd/conf.d/ssl.conf

100行目あたりに、証明書のパスを指定する「SSLCertificateFile」があるので、ファイル名を「localhost.crt」から「wiz-code.private.crt」に書き換えます。

その下、107行目あたりに、秘密鍵のパスを指定する「SSLCertificateKeyFile」があるので、ファイル名を「localhost.key」から「wiz-code.private.key」に書き換えます。

保存、終了したら、Apacheを再起動します。

Apacheを再起動
# systemctl restart httpd.service

では、ブラウザで「https://wiz-code.private/」に接続してみましょう。

HTTPSで接続

「安全な接続ではありません」という警告が表示されます。 内容を見ると、「The certificate is not trusted because it is self-signed.(この証明書は信頼できないよ!なんでかって?自己署名だからさっ!)」と書かれています。 はい、知ってます。 「例外を追加」にすれば証明書が受け入れられるかな?

自己署名証明書に対する警告

もう一段階、セキュリティ警告が表示されました。 ここまでしっかり警告してくれれば、誤って自己署名のSSLサイトを開いてしまうこともないでしょうね。 毎回尋ねられるのもおっくうなので、次回以降は警告しないようにして、セキュリティ例外を承認します。

HTTPSで接続完了

これでようやくページが表示されました。

ちなみに、「接続先サイトのホスト名」と「証明書のCommon Name」が一致しない場合、ちゃんと認証機関で発行した証明書でも警告が表示されます。 くどいようですが、署名要求のCommon Nameは間違えないように!

ファイアウォールでHTTPSを許可

ファイアウォールでHTTPSのポートも外部からでもアクセスできるように開けておきましょう。

今回のSSL対応はひとまずここまで。 SNIの対応は、VirtualHostの設定で複数のサイトを設置するときに行います。

この章のまとめ