Úvod
Zásadním problémem HTTPS bylo po dlouhou dobu pořadí vykonávaných činností, kdy se v prvním kroku vytvořilo SSL spojení, a teprve přes něj se přenesl HTTP požadavek se jménem webu, který klient požadoval. To znamenalo, že webový server nemohl při vytváření SSL spojení vědět, který certifikát má klientovi předložit. V praxi to znamenalo (a bohužel stále v případě mnoha serverů znamená), že na jedné IP adrese mohly být virtuální weby pouze s jedním certifikátem. Pokud jste chtěli použít pro každý virtuální web jiný certifikát, museli jste si zajistit odpovídající počet IP adres a každé IP adrese přiřadit konkrétní certifikát (a webovou prezentaci).
Tento problém se bohužel nedá dost dobře řešit na úrovni certifikátů – i když je možné vytvořit certifikát pro více domén, certifikát může být vydán pouze pro jednu osobu či organizaci. Řešení tedy muselo přijít v podobě rozšíření protokolů SSL a TLS, a právě tomuto rozšíření se říká SNI (Server Name Indication). Toto rozšíření umožňuje prohlížeči předat jméno požadovaného webu ještě před vytvářením šifrovaného spojení, což dává serveru možnost servírovat i na jediné IP adrese různé certifikáty podle toho, který web klient požaduje.
Podpora v prohlížečích
Aby mohlo SNI fungovat, musí být podporováno na straně serveru, ale také na straně klienta. Jako správci serverů máte serverovou část pod kontrolou, tudíž hlavní problém spočívá v podpoře na straně klientů. V této oblasti se sice hnuly ledy a řada prohlížečů dnes SNI bez problémů podporuje, ale ani zdaleka ne všechny a ne na všech systémech. Problémy jsou zejména na Windows XP a mobilních zařízeních, ale i na Linuxu. Aktuální seznam naleznete na Wikipedii. Dle tohoto zdroje SNI podporují následující verze prohlížečů:
IE 7 a výše, ovšem ne na Windows XP, kde SNI v IE nefunguje bez ohledu na verzi
Mozilla Firefox 2.0 a vyšší
Opera 8.0 a vyšší
Google Chrome (na XP až od verze 6)
Safari 2.1 a výše
Android – výchozí prohlížeč od verze Honeycomb
SNI naopak nepodporuje třeba Konqueror, IE a Safari na XP, wget, Windows Mobile až po 6.5, Oracle Java JSSE atd. Co se Konqueroru týče, podpora SNI snad velmi brzy přibude (měla by být součástí verze 4.7), ale než se nový Konqueror dostane do distribucí, chvíli to ještě potrvá.
Jak je vidět, není to sice úplně špatné, ale stejně tak to ještě pořád není to pravé ořechové. Pokud se tedy budete rozhodovat o nasazení SNI, určitě berte na vědomí, že ne všichni vaši klienti jej patrně podporují.
S tím se pojí zásadní otázka – co se stane, pokud váš server navštíví klient nepodporující SNI? Server by měl zareagovat více či méně podle očekávání, tzn. měl by použít výchozí certifikát (obvykle první certifikát v definici virtuálních webů) a po vytvoření SSL spojení naservírovat klientovi správný web. Klient se tedy na web dostane, ale ne bez obvyklého varování o problému s předloženým certifikátem.
Podpora ve webových serverech
Dle Wikipedie podporují SNI webové servery v následujících verzích:
Apache 2.2.12 a výše
Cherokee zkompilované s podporou TLS
lighttpd 1.4 a 1.5 s patchem nebo 1.4.24 a výše bez patche
Nginx 0.5.32 a vyšší, podpora musí být zakompilována a podmínkou je OpenSSL podporující SNI, tj. verze 0.9.8f a vyšší
S výjimkou serveru Apache, kde zmiňuji i řešení pro starší systémy (Debian Lenny), by příklady uvedené níže měly fungovat až v Debianu Squeeze s tím, že na starších verzích Debianu jsem testování neprováděl.
SNI a Apache
Máte-li k dispozici Apache 2.2.12 nebo novější, můžete použít mod_ssl
. Na starších systémech musíte použít mod_gnutls
. Následující ukázka je určena pro mod_ssl
:
Listen 443 NameVirtualHost *:443 <VirtualHost *:443> DocumentRoot /var/www/example1.cz ServerName www.example1.cz SSLEngine On SSLCertificateFile /etc/apache2/example1.pem SSLCertificateKeyFile /etc/apache2/example1.key </VirtualHost> <VirtualHost *:443> DocumentRoot /var/www/example2.cz ServerName www.example2.cz SSLEngine On SSLCertificateFile /etc/apache2/example2.pem SSLCertificateKeyFile /etc/apache2/example2.key </VirtualHost>
Jak je vidět, na samotném nastavení není nic obtížného, postačí klasický NameVirtualHost
a pak jednotlivé virtuální weby lišící se jménem a certifikáty. V případě, že Apache získá požadavek od nekompatibilního klienta, použije certifikát prvního takto definovaného virtuálního webu, tedy v tomto případě to bude example1
.
Pokud byste raději, aby Apache v případě nekompatibilního klienta vygeneroval chybovou hlášku 403 a nedovolil klientovi přístup, nastavte volbu SSLStrictSNIVHostCheck
na „on
“ (výchozí nastavení je „off
“, takže pokud tuto volbu neuvedete, Apache se zachová, jak bylo uvedeno výše).
Máte-li starší systém se starší verzí Apache, zbývá vám kromě možnosti použít novější Apache z backportů jen mod_gnutls
. Konfigurace SNI tímto způsobem by vypadala takto (nezapomeňte modul gnutls
nejprve nainstalovat a aktivovat):
Listen 443 NameVirtualHost *:443 <VirtualHost *:443> DocumentRoot /var/www/example1.cz ServerName www.example1.cz GnuTLSEnable on GnuTLSExportCertificates on GnuTLSCertificateFile /etc/apache2/example1.pem GnuTLSKeyFile /etc/apache2/example1.key </VirtualHost> <VirtualHost *:443> DocumentRoot /var/www/example2.cz ServerName www.example2.cz GnuTLSEnable on GnuTLSExportCertificates on GnuTLSCertificateFile /etc/apache2/example2.pem GnuTLSKeyFile /etc/apache2/example2.key </VirtualHost>
SNI a Lighttpd
Pokud máte aktivovaný modul ssl
, postačí do definice virtuálních webů přidat direktivu ssl.pemfile
s odkazem na soubor obsahující jak certifikát, tak privátní klíč, takto:
$HTTP["host"] == "www.example1.cz" { server.document-root = "/var/www/example1.cz" ssl.pemfile = "/etc/lighttpd/server.pem" } $HTTP["host"] == "www.example2.cz" { server.document-root = "/var/www/example2.cz" ssl.pemfile = "/etc/lighttpd/server2.pem" }
SNI a Cherokee
Cherokee používá SNI již ve výchozím nastavení jako mechanismus pro odlišení SSL virtuálních webů, takže zde není návod třeba. Jediné, na co byste si měli dát pozor, je přiřazení certifikátu výchozímu virtuálnímu serveru, jehož certifikát se použije v případě, že klient SNI nepodporuje.
SNI a Nginx
Použití SNI v případě serveru Nginx je také relativně jednoduché, resp. postačí podobná strategie jako v případě serveru Apache, tj. normálně definovat virtuální weby běžící na portu 443 se zapnutým ssl
(příklad viz níže). Stejně jako u Apache platí i zde, že certifikát prvního virtuálního webu se použije jako výchozí certifikát pro nekompatibilní klienty.
Abyste si ověřili, zdali Nginx podporuje SNI, resp. byl zkompilován s podporou SNI, můžete použít následující příkaz:
nginx -V
Ve výpisu byste měli vidět následující řádku:
TLS SNI support enabled
Pokud ji neuvidíte, nezbude vám než si Nginx zkompilovat ručně. Následuje příklad konfigurace SNI v Nginx:
server { listen 443; server_name www.example1.cz; ssl on; ssl_certificate /etc/nginx/example2.pem; ssl_certificate_key /etc/nginx/example2.key; location / { root /var/www/example1.cz; index index.html index.htm; } } server { listen 443; server_name www.example2.cz; ssl on; ssl_certificate /etc/nginx/example1.pem; ssl_certificate_key /etc/nginx/example1.key; location / { root /var/www/example2.cz; index index.html index.htm; } }
Pár slov na závěr
V úvodu zmíněný problém s HTTPS řeší nejenom SNI, ale také svým způsobem protokol IPv6, i když přechod klientů na IPv6 bude možná podstatně pomalejší než přechod klientů na prohlížeče schopné používat SNI. Faktem nicméně je, že podpora SNI na straně klientů v tuto chvíli stále není bezproblémová a nějakou dobu ještě nebude, což celkem logicky brzdí nasazení SNI na produkční servery.