デジタル証明書

【図解】TLSのSNIの仕組み ~SANsやCN,ワイルドカードとの違い~

SNI と SANs , CN(Common Name) の違い

SNI は TLS ネゴシエーションの中の最初のパケット ClientHello の中に含まれる extension (拡張属性) です。これは主に、1台のサーバ内に複数のドメインを持つ https サーバに対し、クライアントが「どの URL のサイトへ https アクセスしようとしているか」を提示し、適切なサーバ証明書を引き出すために TLS 規格に追加された属性です。

もともとの目的は上記の通りですが、最近では Web フィルタプロキシや UTM などではこの SNI により宛先の URL を認知し、その URL が危険なサイトではないかどうかを検査しています。なのでセキュリティ上でとても重要な役割を担っています。(昔はデジタル証明書のコモンネームや SANs を検査する方式だった。)

一方、SANs は 1 つの証明書で複数の URL をカバーするために作られた、X.509 規格に追加された拡張フィールドです。

つまり、SNI は TLS 通信上の拡張属性、SANs は X.509 規格で示されたデジタル証明書のファイルデータ構造上の拡張フィールドになります。目的も前述の通りに異なります。

  • SNI は TLS ネゴシエーションの最初のパケット ClientHello に含まれる (クライアントが提示する)
  • SANs, CommonName は証明書の中に含まれる (証明書はサーバが提示する)

SNI (Server Name Indication)

SANs と SNI の違い

SANs (サブジェクト代替名) はサーバ側にセットする証明書へ設定する内容でしたが、SNI (server_name indication) はクライアントが TLS によるネゴシエーションを開始する Client Hello パケット内にセットされる extension (拡張属性) です。

つまり SANs は「証明書に関するサーバ側の話」であり、SNI は「TLS に関するクライアント側の話」になります。

SNI の本来の役割と使い方

バーチャルドメインを使って 1 つの IP アドレスで複数の https サイトを運用しているケースでは、クライアントからの https アクセス時に『どのサイトへアクセスしようとしているのか』という情報が無いと、サーバー側はどのサーバー証明書を提示して良いか分かりません。

なぜなら、本来は http ヘッダ内の [Host: ] 属性を見てどのドメイン宛なのかを識別するのですが、https の場合は http ヘッダが送られる前に TLS ネゴシエーションで証明書を提示しなければならないからです。

SNI とは、クライアントが TLS セッション開始時の "Client Hello" メッセージにおいて "server_name indication" Extension を使ってサイト名をサーバに知らせる方法のことです。

以下に、このサイト(https://milestone-of-se.nesuke.com) にアクセスした際の Client Hello のパケットキャプチャを示します。

Extension: server_name の "Server Name" に本サイトの URL が示されていることが分かります。サーバー側はこの情報を見て、TLS Certificate において、どの証明書を提示するかを判断することができます。

SNI の応用的な使い方と暗号化の傾向

NW エンジニアにおける SNI の位置付けは、『UTM での宛先識別およびそれを応用したURLフィルタリングで使うもの』と言ってもよいでしょう。

近年のサービスのクラウド化により、ある URL (例えば www.google.com) へのアクセス先 IP アドレスは多数の IP アドレスが使われるケースがままあります。そのような場合、その IP アドレスを1つ1つ把握しUTMに設定していくのは困難です。

UTM にて特定の URL でアクセス制御するには、この SNI を見ます。

httpが主流の時代においては宛先 URL は前述の通り http の [Host 属性] で識別していましたが、https が主流の現在においては http ヘッダは暗号化されて NW 機器からは見えません。なので、暗号化されていない SNI を見るのです。

【図解】UTMとhttpsの関係 ~SSL復号とSNIインスペクションについて~
UTMとは ファイアウォールはセキュリティのためのアプライアンス NW 機器です...

ただし、最近の傾向として、SNI も暗号化しよう (ClientHello 自体を暗号化しよう) という向きもあります。そうなったら UTM での URL 宛先制御はできなくなるかもしれません。

【図解】DNSのHTTPSレコード(type65)とECH(ESNI)の仕組み
新たな DNS RR と DNS に以下の新たな RR (リソースレコード) が...

SANs (サブジェクト代替名, サブジェクトの別名) とコモンネーム

デジタル証明書 (サーバ証明書, SSL 証明書) では暗号化だけでなく認証も行うことができます。

例えば Web サーバにデジタル証明書をセットし、https を使うようにする場合、パケットの暗号化だけでなく、「その Web サーバが本当に正しいものか?偽装サイトではないのか?」といった認証を行います。

なのでデジタル証明書は正しく作成しないと、クライアントから https 等のアクセスをする際にエラーが表示されてしまいます。

Web サーバの正しさを証明するためにいくつか観点があるのですが、その観点のうちの 1 つが、「証明書が示すホスト名 (FQDN)」と「ユーザがブラウザに入力したホスト名 (FQDN)」が一致するかどうか?というものです。

証明書が示すホスト名は、証明書にあるサブジェクト属性の中にある「コモンネーム」が知られていますが、現在は SANs (サブジェクト代替名) を使うのが主流です。「サブジェクトの別名」と呼ぶこともあります。

以下は 本サイトの証明書の例です。赤枠がサブジェクトの CN (Common Name) であり、青枠がサブジェクト代替名です。

IE (Internet Explorer) ではコモンネームとサブジェクト代替名の両方を見ているようですが、Chrome 等は「サブジェクト属性は無視する(つまりその中にあるコモンネームは見ない)、SANs のみで確認を行う」と宣言しています

Chrome Deprecates Subject CN Matching
If you’re using a Self-Signed certificat...

Chrome 58 will require that certificates specify the hostname(s) to which they apply in the SubjectAltName field; values in the Subject field will be ignored.

実際、SANs に FQDN を含んでいない場合は、例えコモンネームに値が入っていても Chrome では「NET::ERR_CERT_COMMON_NAME_INVALID」のエラーが表示されます。(IE ではエラーになりませんが、Edge は Chrome ベースなのでやはりエラーになります。)

SANs (Subject Alternative Names)

SANs とは本来的には「サブジェクト≒コモンネーム」の代わりとなる名前であり、コモンネームとは別に、URL として使うことを許された名前のことなのですが、前述の通り、今では偽装サイトか否かのチェックは SANs のほうがメインで使われます。

例えば Yahoo!JAPAN (https://yahoo.co.jp/) の証明書を見てみましょう。(Chrome の URL 左横の鍵マークをクリックし、「証明書」をクリックし、ポップアップした証明書の「詳細」タブをクリックすると、以下の画面が表示されます。)

サブジェクト代替名に yahoo.co.jp が含まれていることが確認できます。

サブジェクト代替名は、その Web サーバが複数の FQDN URL を持つ場合やテスト用に URL を変更する場合などに使われます。

ワイルドカード

ワイルドカードを使うと、その表現に合致した URL を持つ複数のサーバに使い回すことができます。

先程の Yahoo JAPAN の証明書ですが、サブジェクト代替名の上の方に *.yahoo.co.jp 等の * (アスタリスク) で始まるものがたくさんあります。

このアスタリスクは「ワイルドカード」と呼ばれ、任意の文字列と解釈されます。

なので例えば www.yahoo.co.jp といったサブドメインサイトであっても、この証明書を使えば「正しい URL」と解釈されます。

ワイルドカード証明書は『.yahoo.co.jp』で終わる FQDN ホスト名 (例えば www2.yahoo.co.jp や mail.yahoo.co.jp 等) のサーバであればどれにでも利用可能です。なので秘密鍵とセットでコピーして使いまわしができます。

コメント

タイトルとURLをコピーしました