Jak nasadit HTTPS na vlastním serveru


Obsah:

Úvod

Zabezpečení komunikace s webem pomocí šifrovaného protokolu HTTPS již dnes není nic, co by používaly pouze banky, webmaily nebo jiné služby, které pracují s citlivými údaji. Dnes by se HTTPS mělo používat na co nejvíce službách, protože s rozmachem smartphonů a cestování se připojujeme k hromadě sítí (kavárny, letiště, restaurace, knihovny, ...), přičemž některé jsou na tom s důvěryhodností ne úplně dobře.

Útok na takové veřejné Wi-Fi není nic drahého ani technicky náročného, přičemž následná manipulace s nezašifrovaným provozem není o nic těžší a může mít nepěkné následky, jak koneckonců dokazuje například tato přednáška od Tomáše Hály z webhostingové společnosti Active24. Pokud náhodou máte web u této společnosti, tak už HTTPS nasazené máte, a možná o tom ani nevíte. :-) HTTPS proti těmto útokům brání, přičemž pokud se kdokoliv pokusí do provozu zasáhnout, tak se zobrazí celoobrazovkové varování, že certifikát je neplatný. Toto jste jistě už někdy zažili. Pouhé čtení tohoto provozu už je zapovězeno principielně, a to právě již zmiňovaným šifrováním.

Nemusí však jít pouze o nedůvěryhodné veřejné Wi-Fi sítě. V některých zemích se to děje i na normálním placeném připojení, např. v Číně. Můžete sice namítat, že tady v Číně nejsme, nicméně co když se vám nebo vašemu ISP někdo nabourá do routeru či klidně přímo do počítače? Pouze jednoduchým změněním adres DNS serverů se dají dělat divy. Odkloní doménu na útočníkovu IP adresu a pár transparentních proxy serverů se už o "legrácky" postará. Tomuto se říká DNS hijacking.

Rozmach HTTPS navíc není nijak malý, jak ukazuje například tento graf od certifikační autority Let's Encrypt, o které v tomto článku ještě uslyšíte. Pokud chcete i jinou motivaci, tak vězte, že již od roku 2014 dává Google malinko bodíků vaší stránce navíc, pokud běží přes HTTPS, takže se můžete ocitnout o malinko výše ve výsledcích (no dobře, nijak extrémní boost to nebude, ale vždyť pro bodík navíc v Googlu uděláte cokoliv, nu ne? :-)). Proč se tedy nepřipojit k 90% načteným stránkám a nezavést HTTPS taky?

V tomto článku vám ukáži, jak HTTPS nasadit na vlastním serveru, tzn. nějakém, na kterém máte roota (ať už je to server fyzický, nebo VPS). Pokud používáte sdílený webhosting (jako ostatně asi většina lidí), HTTPS si musíte nastavit u nich. V dnešní době již není výjimkou, že se tak dá učinit prakticky na jeden klik v administraci a vůbec se nemusíte pouštět do nějakých terminálových machinací, které budu popisovat níže. Jestliže takovou možnost nenajdete, kontaktujte customer support. Pokud je dotyčný hosting alespoň trošku slušný, to možnost by vám dát měl. Některé hostingy dnes už HTTPS s validním certifikátem zapínají automaticky a ani o tom třeba nevíte (stejně tak činí různé reverse proxy as-a-service typu Cloudflare).

Nutno podotknout, že ukázku budu provádět na operačním systému Debian 10 Buster s webserverem Apache 2.4. Pokud bude vaše prostředí jiné, nemusí vše fungovat správně, stejně jako když se mými pokyny budete řídit o nějaký ten měsíc/rok dále (dnes je 1. 1. 2020, abyste se orientovali) a může to nadělat neplechu. Jestliže se cokoliv pochroumá, nenesu za to zodpovědnost; vše děláte na vlastní nebezpečí. I zde platí pravidlo, že byste měli pravidelně zálohovat. Zároveň podotýkám, že mířím výhradně na malé, nekomerční a osobní prezentace, kde nebude vadit, když něco chvilku nepoběží. Pro nějaké větší nasazení je dobré se vzdělat jinak a jinde.

Informace se budu snažit podávat detailně a budu vysvětlovat na první pohled nejasné pojmy. Za cíl si dávám, aby to zvládl i naprostý laik a Linuxu neznalý uživatel. Teď už proto nikdo nebude moct říci, že je to moc složité. :-) Proto bude článek dost dlouhý a ukecaný. Pokud se vám tento styl nelíbí, tak si můžete samozřejmě najít nějaký jiný; podobných (a stručnějších) článků je na webu mnoho; na spodku stránky jsem vám vypsal seznam. Pojďme tedy na to.


1. Získání certifikátu

Aby si klient mohl ověřit, že jsou naše stránky opravdu ty naše a nikdo mu je po cestě nepodvrhl ani nerozšifroval, musíme mít důvěryhodný certifikát. Nyní si ukážeme, jak ho získat. Nebojte se však, je to, narozdíl od dob minulých, dnes všechno zdarma a automaticky.

Důvěryhodné certifikáty vydává entita, které se říká certifikační autorita (dále CA). Jednou z nich je Let's Encrypt, která z této množiny vyniká tím, že jsou její certifikáty naprosto zdarma, a to jak pro komerční, tak nekomerční použití. Certifikáty od této CA mají platnost 90 dnů (cca 3 měsíce) a získávají se a obnovují se zcela automaticky (pokud si neřeknete, že to tak nechcete).

První krok, co musíme udělat, je stáhnout nějakého klienta, který umí komunikovat po protokolu ACME, který se domluví s CA. Jedním z nich je acme.sh. Klient se spojí s certifikační autoritou, ta si ověří, že komunikuje opravdu s námi (aby si nikdo jiný nemohl důvěryhodný certifikát udělat pro cizí doménu a poté se za ni vydávat) a pokud je ověření úspěšné, certifikát nám vydá. Tento klient je můj oblíbený a vyznačuje se tím, že je napsán přímo ve skriptovacím jazyce shellu – bashi. Žádné C++, žádný Python ani hromada dalších závislostí.

Nejprve nainstalujeme program curl následujícím příkazem:

sudo apt install curl

Je ale docela možné, že ho již nainstalovaný máte, aniž byste o tom věděli; je poměrně populární a používaný. Ten bude použit pro samotné stažení skriptu a později pro komunikaci skriptu s CA.

Poté již můžeme stáhnout a naistalovat samotný acme.sh pomocí příkazu:

curl https://get.acme.sh | sh

Skript se sám nainstaluje do vašeho domovského adresáře a po dalším spuštění terminálu ho bude možné používat jednoduchým zadáním příkazu acme.sh. Jedna z pěkných vlastností tohoto skriptu je, že pro jeho instalaci není třeba být přihlášen jako root, címž se liší od klasických instalací balíčků pomocí apt apod. Bez těchto oprávnění ho lze i spouštět a používat mj. v tzv. webroot modu, který budeme používat.

Pro pokročilejší: pokud nechcete instalovat skript takto, můžete si ho naklonovat z GitHubu. Vše je open-source, takže žádný problém.

Nyní už jsme připraveni na získání samotného certifikátu. Mějme doménu www.priklad.cz, která má webroot (tzn. kořenová složka webu, odkud se servírují soubory) v /var/www/html (pozn. na konci cesty by nemělo být lomítko).

Důležité je říct, že do složky musíte mít právo zapisovat pod uživatelem, pod kterým skript spouštíte (pozn. pod rootem toto z principu řešit nemusíte; root může totiž vše). Stejně tak pokud vám nějaký redakční systém odchytává všechny požadavky, tak mu musíte nařídit, aby to nedělal pro složku <webroot>/.well-known/acme-challenge/ a její podsoubory. Jestliže máte domén víc, stačí přidat víc argumentů -d <doména>. Skript se s tím umí poprat.

Pokud jste se ujistili, že vše je nastaveno jak má, stačí už spustit příkaz podobný tomuto, kde nahradíte doménu/y a webroot za ten váš:

acme.sh --issue -d www.priklad.cz -w /var/www/html --reloadcmd "service apache2 force-reload"

Gratuluji, váš certifikát, privátní klíč a další soubory jsou nyní na cestách, které jsou uvedeny na posledních 4 řádcích výstupu. Nás budou zajímat soubory fullchain.cer a <vaše_doména>.key, ale k tomu až později. Certifikát by se zároveň měl vždy před vypršením obnovit, pokud vše bude fungovat. Zároveň se restartuje Apache, aby se obnovený certifkát vždy ihned použil (k tomu slouží argument --reloadcmd).

Ukazuje-li se nějaká chyba, tak zkontrolujte překlepy, práva k zápisu, špatně fungující redakční systémy apod., a pokud zde neuspějete, tak si prostě jen přečtěte, co se stalo špatně a pokuste se to vyřešit. Chyby jsou většinou vypisovány lidsky i s nějakými návrhy řešení (žádné nicneříkájící chybové kódy v šestnáctkové soustavě zde nečekejte). Nebo, ostatně jako vždy, zkuste pogooglit; žádnou chybu jako první na světě řešit nebudete.

Pro pokročilejší: skript je automaticky spouštěn démonem cron, aby docházelo k obnovení, je-li to potřeba. Pokud se chcete přesvědčit, že skript je ve cronu zanesen, spusťte příkaz crontab -l a jestliže ve výstupu najdete řádek s acme.sh, vše se správně nastavilo.

Tímto už bychom tu nejdůležitější část měli za sebou a nyní se můžeme přesunout na samotnou konfiguraci webserveru tak, aby byl certifikát používán.


2. Nastavení modulu ssl

Dobrá, certifikát máme, a co dál? Nejdříve zapneme modul ssl, který webovému serveru Apache přidává schopnost komunikace s klienty pomocí protokolu HTTPS.

Apache ve výchozím stavu nemá modul ssl zapnutý. Na zapínání modulů je zde však jednoduchá utilitka a tak to nebude nic těžkého. Modul povolíme spuštěním příkazu:

sudo a2enmod ssl

Kýžený modul se nám aktivuje a utilitka nám správně říká, že bychom měli server restartovat. My to zatím dělat nemusíme, nicméně pokud jste to již udělali, ničemu to nevadí. Server bychom totiž zbytečně restartovali několikrát.

Pro pokročilejší: Aktivací HTTPS se vám zpřístupní možnost využití nového protokolu HTTP/2, který může zrychlit načítání stránek. Má to však jeden háček: vaše instalace webserveru Apache nesmí používat MPM modul prefork. To se mj. stává, když máte zaplý mod_php (a PHP nepoužíváte přes FastCGI). Vámi použitý MPM můžete rozpoznat např. příkazem ls -lAh /etc/apache2/mods-enabled/mpm_*.load Jste-li si jisti, že máte zaplý MPM event nebo worker, můžete modul aktivovat pomocí sudo a2enmod http2


3. Nasazení certifikátu a samotné zprovoznění TLS

Nyní již konečně můžeme přejít k části, na kterou jste všichni čekali. Už se totiž budeme na náš web moci připojit pomocí HTTPS.

Mějme tedy opět výchozí konfiguraci, kdy je váš web poháněn tzv. virtuálním hostem (dále vhost), jehož definiční soubor se nachází na /etc/apache2/sites-available/000-default.conf. Vhost je používán Apachem i jinými web servery, aby mohlo být hostováno více webů na jedné IP adrese (zjednodušeně řečeno). Tento vhost musíme nyní "zdvojit", protože HTTPS a HTTP používají rozdílnou konfiguraci (oproti HTTP musí být ve vhostu pro HTTPS uvedeny certifikáty a klíče a naopak ve vhostu pro HTTP by mělo být přesměrování, ale k tomu až později).

Přejděme tedy do složky s vhosty a zkopírujeme ten náš např. následující dvojicí příkazů:

cd /etc/apache2/sites-available/
sudo cp 000-default.conf 000-default-https.conf

Nyní otevřeme nově zkopírovaný konfigurák např. editorem nano:

sudo nano 000-default-https.conf
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /home/user/.acme.sh/www.priklad.cz/fullchain.cer
SSLCertificateKeyFile /home/user/.acme.sh/www.priklad.cz/www.priklad.cz.key

# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
...
                                    

Samozřejmě nezapomeneme přepsat cesty k certifikátu a privátnímu klíči tak, aby odpovídaly skutečnému stavu našeho serveru.

Po dokončení editace ukončíme editor (nano: Ctrl + O, Enter, Ctrl + X) a můžeme si nově vytvořeného vhosta povolit. To se dělá velice jednoduše:

sudo a2ensite 000-default-https

Gratuluji, máme většinu úkonů za námi. Nyní bychom ještě měli zprovoznit přesměrování na HTTPS.


4. Přesměrování z HTTP na HTTPS

HTTPS nám už sice běží, nicméně všichni uživatelé budou chodit stále na nezabezpečenou verzi po HTTP, protože jsou na ni namířeny odkazy i vyhledávače a ono to přece funguje, tak to nemá nikdo potřebu měnit. K přechodu je tedy musíme donutit. Velice nenásilnou a automatickou formou je přesměrování. Uživatel nic nepozná a přece ho to (ve většině případů, viz. útok SSLStrip) ochrání. Není to nic složitého, takže pojďme na to.

Nejdříve musíme povolit Apache modul rewrite, který bude přesměrování zařizovat. Schválně zkuste hádat, jak se to bude dělat:

sudo a2enmod rewrite

Je dost možné, že modul budete mít již povolený; je to jeden z těch nejpoužívanějších. Ale nic neuškodí si to pro jistotu zkontrolovat. Jsme-li stále ve složkce s vhosty (/etc/apache2/sites-available/), tak otevřeme náš původní HTTP-only vhost s názvem 000-default.conf opět v nějakém editoru a v podstatě kamkoliv přidáme následující dva červeně vyznačené řádky; já je budu přidávat hned nahoru pod direktivu VirtualHost:

<VirtualHost *:80>
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]

# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
...
                                    

Na porozumění konfiguraci modulu rewrite je už potřeba trochu znát regulární výrazy apod., takže se vysvětlením nějak zaobírat nebudeme. Prostě to budeme brát jako hotovou věc. Nyní mohu s klidem říct, že jsme u konce. Teď už stačí jen restartovat webserver a vše by mělo běžet.


5. Restart serveru!

Nyní už nám bude stačit spustit jediný příkaz a vše by mělo fungovat:

sudo service apache2 restart

Webserver jsme nyní restartovali. Pokud jste si výraz „restart webserveru“ vyložili tak, že máte stroj fyzicky restarovat, ničemu to nevadí; efekt to bude mít stejný.

Ukázala-li se při restartu serveru nějaká chyba, tak vězte, že se to stává celkem běžně; překlepy hold stávají. Zkontrolujte si tedy, zda-li jste vše udělali tak, jak jste měli a zkuste server restartovat znovu. Pokud ani to nepomůže, tak Apache má záznam chybových v souboru /var/log/apache2/error.log. Soubor si tedy vypište (např. příkazem cat /var/log/apache2/error.log) a zkuste najít řádek (většinou bude někde vespod výstupu), který je pro vás relevantní. Podle dotyčného hlášení se můžete chybu pokusit opravit a pokud si nebudete vědět rady, vždy zde platí, že Google ví všechno a nebudete první, kdo problém kdy řešil. Chvilka hledání nikdy neuškodí.

Tímto bychom měli práci dokončenou. Můžete přejít na vaše stránky a kochat se tím, jak jsou zabezpečené. :-)

HTTPS funguje :-)

Pozn.: Pokud jste si stránky prošli a přišli jste na to, že vám nefungují nějaké skripty, styly, obrázky apod., jedná se o problém tzv. mixed contentu neboli smíšeného obsahu. Vyřešit se to dá tak, že najdete na stránce veškeré absolutní odkazy (tzn. ty, jejichž atribut src nebo href začíná na http://) a přepíšete u nich protokol na https://. Více se o tom můžete dozvědět napříkad zde nebo zde.


Závěr

Tímto bychom byli u konce a váš web by měl být zabezpečený. Když se na to teď zpětně dívám, tak si skutečně říkám, že jsem to s tou délkou možná trošku přepísk, ale na druhou stranu si říkám, že, jak již bylo zmiňováno výše, si už teď nikdo nebude moci stěžovat, že je pro něj přechod na HTTPS moc těžký.

Je zde ještě pár věcí, které by mohly zabezpečení zlepšit, např. HSTS, nicméně si myslím, že k tomu návodu mířeného na začátečníky to úplně nepatří, protože pokud si tyto věci špatně nakonfigurujete, můžete si tím váš web i na pár měsíců znepřístupnit.

Zaujalo-li vás toto téma, přikládám ještě několik zdrojů, ze kterých byste se mohli něco přiučit (všimněte si, že veškeré odkazy vedou na weby s HTTPS :-)):


Odkazy