Server Name Indication

Server Name Indication（SNI、サーバー ネーム インディケーション、サーバ名表示）は、SSL/TLSの拡張仕様の一つである。SSLハンドシェイク時にクライアントがアクセスしたいホスト名を伝えることで、サーバ側がグローバルIPごとではなくホスト名によって異なる証明書を使い分けることを可能にする。

SNIは特に、HTTP 1.1の名前ベースバーチャルホストをHTTPSに対応させるために使われる。SNIを機能させるには、Webサーバ側とブラウザ側両面の対応が必要である。SNIを実装しないブラウザでは全てのホスト名で同じサーバ証明書が使われるため、警告が表示されることがある。2016年時点でPC・モバイルの主要なブラウザで問題なく利用できる状況である。

問題の背景

SSL/TLS接続のはじめに、クライアントはSSL/TLSのサーバから（サーバとCAの）証明書を受け取り、証明書の改ざんされていないことなどを確認する。サーバ証明書にはホスト名が書かれており、それが今接続しようとしているホスト名と一致することをクライアントは確認する。そうでない場合、なりすましや中間者攻撃の恐れがあるため、クライアントはユーザに警告をする。ユーザの責任で証明書を信用し、警告を迂回することができるアプリケーションも存在する。

HTTPの場合、名前ベースバーチャルホストを使うと、複数のホスト名（同一のドメインであれ、異なるドメインであれ）を単一のサーバと単一のグローバルIPで運用できる。これは、ブラウザ側がHTTPヘッダによって希望のホスト名を指定することで働く。しかし、HTTPSの場合、HTTP要求をやりとりする前にSSL/TLSハンドシェイクを行う必要がある。このため、ブラウザがどのホストを訪問するかを、ハンドシェイク時点でサーバ側には予測できず、HTTPヘッダのホスト名によって複数枚のサーバ証明書を使い分けることができない。したがって、単一のサーバで複数枚のサーバ証明書を使い分けるには名前ベースバーチャルホストは利用できず、ホスト名ごとに異なるグローバルIPを使う必要があった（IPベースバーチャルホスト）。

この問題への対処方法として、1枚のサーバ証明書に複数のホスト名を指定する手段が知られていた。X.509 v3の証明書で導入されたsubjectAltName拡張を利用することで、追加のホスト名を指定できる。通常、主体者のCommon Name属性同様、こちらでもワイルドカードを使える。しかし、実運用においてサーバの運用する全てのホスト名を予めCSRに含めておくことは現実的ではなく、ホスト（ワイルドカードの場合、ドメイン）名が増えるたびに別々にサーバ証明書を導入することが多い。2005年から、CAcertはTLSをバーチャルホスト下で使う方法について様々な実験を行なったが、多くは非実用的なものだった。例えば、subjectAltName拡張を使って運用する全ドメインのホスト名を1枚のサーバ証明書に集約し、ドメインが増えたりドメイン名が変わったりするごとに取得しなおすという方法が提案された。

これらの事情によって、複数のサーバ証明書を使い分けたいサーバは、単数または少数のホスト名をIP別に運用することが要求される。ホスト（ワイルドカードの場合、ドメイン）名ごとに別のグローバルIPを取得することはコストがかかる（IPアドレス枯渇問題）ため、多くのWebサイトにはHTTPS通信の利用はハードルが高かった。

SNIによる解決

Server Name Indication（SNI）では、TLSに拡張を加えることでこの問題に対処する。TLSのハンドシェイク手続きで、HTTPSクライアントが希望するドメイン名を伝える（この部分は平文となる）。それによってサーバが対応するドメイン名を記した証明書を使うことが可能になる。サーバとクライアントが共にSNIに対応していれば、一つのIPで複数のドメインにHTTPSサーバを提供することが可能になる。

SNIは2003年6月、「TLS拡張仕様」に加わった。その後更新され、2014年1月現在、SNIの記述のある最新の仕様は (日本語訳) である。

SNIの暗号化 
SNIも暗号化する方法が検討されている。当初、Encrypted SNI (ESNI)が検討されていたものの、その後Encrypted Client Hello (ECH)が考案され、標準化に向けた検討が進められている。

対応状況 

SNIに対応するには、アプリケーションの使うSSLライブラリがホスト名を受け取る仕組みが必要である。OSの機能を利用してSSL通信を行うアプリケーションでは、OSのSSL機能がSNIをサポートしない場合はSNIを使うことはできない。2011年の時点でほとんどのブラウザやSSLライブラリはSNIを実装したが、ユーザの使うOSとの組み合わせによってはSNIを利用できない場合がしばしばある。

対応ソフト 
2004年に、OpenSSLでTLS/SNIをサポートするパッチがEdelKeyプロジェクトによって作成された。このパッチは2006年開発ブランチに取り込まれ、2007年にOpenSSL 0.9.8にポートされた。

 TLS/SNIをサポートするブラウザ

 Internet Explorer 7 以降（Windows Vista以降のみで、Windows XPではInternet Explorer 8でも非対応）
 Mozilla Firefox 2.0 以降
 Opera 8.0 (2005年) 以降 (設定でTLS 1.1を有効にする必要がある)
 Opera Mobile 10.1 β 以降 (Android) 
 Google Chrome (Windows Vista以降。バージョン6でWindows XPに対応。Chrome 5.0.342.1でMac OS X v10.5.7以降に対応)
 Safari 3.0 以降（Mac OS X v10.5.6以降、Windows Vista以降、iOS 4.0以降)
 Konqueror/KDE 4.7 以降 
 Android ブラウザ (Android 3.0 (Honeycomb) 以降)
 Windows Phone 7 
  (Maemo)

 Webサーバ

 Apache 2.2.12 以降 + mod_ssl もしくは mod_gnutls
  3.2.0 以降
  (コンパイル時TLSサポートを有効にした場合)
 lighttpd 1.4.24以降 (それ以前の1.4.xはパッチ)
 Nginx と OpenSSL
 F5ネットワークス Local Traffic Manager 11.1 およびそれ以降 
  8.6またはそれ以降
 IBM HTTP Server 9.0 およびそれ以降  
 LiteSpeed 4.1 およびそれ以降
 Pound 2.6 以降
 Apache Tomcat (Java 7 およびそれ以降)
 Microsoft IIS 8
 PageKite tunneling reverse proxy
 Citrix NetScaler 9.3 以降 
 Radware Alteon ADC (AlteonOS 28.1 以降) 

 ライブラリ

 Mozilla NSS 3.11.1 client-side only
 OpenSSL
 0.9.8f (released 11 Oct 2007) - '--enable-tlsext' オプションを明示的に指定する必要がある
 0.9.8j (released 07 Jan 2009) through 1.0.0 (released 29 March 2010) - デフォルトで対応
 GnuTLS
 wolfSSL (デフォルトでは無効だが '--enable-sni' or '--enable-tlsx' オプションにより利用可能)
  1.2.0およびそれ以降 (デフォルトで有効)
 libcurl / cURL 7.18.1 (30 Mar 2008)
 Python 3.2 (ssl, urllib[2] and httplib モジュール) 
 Qt 4.8
 Oracle Java 7 JSSE 
 Apache HttpComponents 4.3.2 
 wget 1.14 (1.14以前はパッチによる
 Android 2.3 (Gingerbread) (ただし部分的、HttpsURLConnection クラスを使った場合に限り対応)
 Android 3.0 (Honeycomb) 
 IO::Socket::SSL (Perl/CPANモジュール, 1.83以降)
 Pike 7.9.5 (SSL module)

非対応ソフト 

以下の組み合わせのソフトウェアはSNIに対応していない。

 クライアント

 Internet Explorer 6 もしくはWindows XP以前での全バージョン
 Safari （Windows XP上)
 BlackBerry ブラウザ (7.1またはそれ以前)
 Windows Mobile 6.5
 Android 2.x のブラウザ (Honeycomb for tablets と Ice Cream Sandwich for phones では対応)
 wget 1.14未満 (パッチによって対応可)

 サーバ

 ライブラリ

 Qt 4.7
 Mozilla Network Security Services server side 
 Java 1.6 およびそれ以前 
 Apache HttpComponents 4.3.1 およびそれ以前 
 Python 2.x (ssl, urllib[2], httplib モジュール) 
 PhantomJS 1.x

脚注

関連項目 

 HTTPS
 Transport Layer Security

外部リンク 
   (旧  (旧 ))
 https://decoder.link/sslchecker/ ブラウザがSNIに対応しているかテストできるサイト
 RFC6066の日本語訳

Transport Layer Security
Hypertext Transfer Protocol
3546