【HTTPS】サーバー証明書の検証についてざっくりとまとめてみました

HTTPS通信を行うときにサーバー証明書を検証する必要があります。この検証って何やってるの?をざっくりまとめてみました。
2021.03.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部の熊膳です。 先日、IoTの案件でデバイスからクラウドへHTTPS接続する際に、デバイス側でサーバー証明書の検証って何をやっているの?という話題になりました。 せっかくですのでブログに簡単にまとめてみます。

はじめに

はじめに大事なことを書いておきます。

サーバー証明書の検証のルールは検証する側で決める

考えてみると当たり前なのですが、ブラウザを使用したHTTPS通信の場合はブラウザがいい感じでやってくれるので忘れがちです。 IoTデバイスの場合は、この部分を自前で用意する場合がありますが、基本的には、サーバーを信頼できると判断するためのルールを自分で決めればよいです。

とはいえ、一般的な検証方法というのがいくつかあるので、紹介します。

ちなみにサーバー証明書というのは、これのことです。

検証方法

今回紹介する検証は、サーバー証明書を用いて、クライアント側(接続する側)が、接続先のサーバーを信頼してよいかを判断する方法のこととして説明します。 念のためですが、最初に書いたとおり検証方法は検証する側で決めることなので、あくまで参考例となります。必ずしも全部の方法を行う必要がないですし、他のやり方や、順番も自分で決めていいです。

サーバー証明書の確認

なにはともあれ、サーバー証明書の確認をまずは行います。この確認は、サーバー証明書が認証局で発行されたかの確認です。PKIについての解説は省きますが、証明書を使って検証するためには、その証明書が改ざんされていないこと(とある認証局で発行されたことが確認できること)が大事です。

これは、署名を確認することで行います。署名とは、サーバー証明書の情報をハッシュした値を認証局の秘密鍵で暗号化したものです。 以下が等しいことで確認できます。

  • 署名をサーバー証明書に含まれる公開鍵で複合した値
  • クライアント側でサーバー証明書の情報をハッシュした値

これで(とある)認証局が発行した証明書ということが確認できます。

署名した認証局が信頼できるか

認証局が発行したことがわかっても、その認証局を信頼してよいかとは別の話です。ツールを使うことで簡単に認証局になれますし、証明書の発行も可能です。

実は、認証局自身も上位の認証局によって署名することができます。証明書Aを署名した認証局Aは、認証局Bで署名されている、認証局Bは、認証局Cで署名されている・・・というようにです。この時、クライアント(接続する側)が認証局Cを信頼できるのであれば、認証局Cが署名した認証局Bも信頼できますし、認証局Aも信頼できますし、最終的には証明書Aも信頼できるという考えです。

DevelopersIOの場合は、中間認証局のAmazonで署名されています。私のMacでは、Amazon Roor CA 1を信頼できるルート認証局の証明書として登録してあるので、結果として、DeveloersIOのサーバー証明書も信頼できるということになります。

サーバー証明書の発行者名がAmazonになってます。

中間認証局のAmazonの発行者名がAmazon Root CA 1になっています。

このように認証局のチェーンをさかのぼって、クライアントが信頼できる認証局にたどり着けば、信頼できると判断していいということです。

詳しく知りたい人は、Issuer Subjectあたりで検索してください。

接続先が正しいか

接続先が正しいのかを確認します。接続したサーバーから送られてきたサーバー証明書が信頼できるものであっても、そもそも接続先が正しくないと話になりません。 そのため、接続先が正しいか(期待した接続先か)を確認します。

以下が等しいことで確認します。

  • 自分が接続した先のドメイン
  • サーバー証明書のSANの値、もしくはCN

自分が接続した先のドメインはわかりますね。ブラウザの場合はlocationに表示されているドメインです。IoTのデバイスの場合は、エンドポイントのドメインですね。

比較するサーバー証明書側のドメインですが、いくつかあって、最近の主流はSAN(Subject Alternative Name)を参照する方法です。Chrome(Mac版)の証明書表示では、「拡張領域」の「サブジェクト代替名」として記述されている部分です。

もしくは、SubjectのCommonNameを参照し比較します。Chromeの証明書表示では、「サブジェクト名」の「通称」部分です。

ただしCommonNameと比較するのは、最近は非推奨とされているので使わないほうがいいと思います。

とはいえ、最初に書いたように、サーバー証明書の検証ルールは検証する側で決めるので、自分で実装する場合は、H/Wのスペックや採用するライブラリなどの制限の中で決めれば良いと思います。

有効な証明書か

最後に、証明書が有効かどうかです。証明書が正しく、接続先も正しいですが、その証明書事態が無効であれば意味ないですよね。

有効かどうかの判断は、主に以下を確認します。

  • 有効期限
  • 失効されていないか

有効期限は、証明書のNot BeforeとNot Afterの範囲内にあるかどうかを確認します。範囲内にあれば有効です。Chromeの証明書表示では、「有効になる日付」と「無効になる日付」です。ここTimeZoneを正しく見てくださいね(昔ポカしたことあります)。

失効されていないかの確認は、CRL(証明書失効リスト)を使うやり方や、OCSPを使うやり方があります。

CRLを使う場合は、証明書のシリアル番号がCRLにあるかないかを確認することになります。CRLを定期的にダウンロードする必要があり、なかなか運用大変です。CRLはChromeの証明書表示では、「拡張領域」の「CRL配布ポイント」のURLからダウンロードすることになります。

OCSPは、CRLのようにファイルをダウンロードして比較するのではなく、オンラインでチェックする仕組みです。Chromeの証明書表示では、「拡張領域」の「オンライン証明書状況プロトコル」のURLで確認することになります。(正直10年以上前に触っただけなので、ほとんど忘れちゃってます)

ポイント

有効かどうかの確認の大事なポイントとして、サーバー証明書だけではなく、チェーンしている認証局が有効かどうかの確認も行う必要があります。認証局の有効期限が切れてたり無効だったら、ダメですよね。

まとめ

サーバー証明書の検証について、ざっくりとまとめてみました。上記以外にもあると思いますし、上記に書いてあることを全部やらなくても当然ありです。独自の拡張フィールドの値を参照するという独自ルールもありです。

サーバー証明書の検証のルールは検証する側で決める

IoTデバイスの場合は、いろいろ制限があると思いますので、検証する側で、この方法で確認できればOKと言えればよいと思います。

以上、どなたかの参考になれば幸いです。