HSTS = zákaz přístupu přes http

HSTS je zkratka pro HTTP Strict Transport Security.

Pomocí http hlavičky prohlížeči řeknu, že z mého serveru už nesmí zobrazovat obsah načtený přes nezabezpečené http, ale vždy pouze přes zabezpečené https.

Na příkladu útoku vysvětlím, proč je takové chování prohlížeče potřeba. Ukážu, jak to funguje s hlavičkami a jak se to nastavuje na serveru Apache.

Útoky man-in-the-middle - Úvodní varování - Podoba HSTS hlavičky - Nastavení HSTS pomocí .htaccess - IncludeSubDomains - Preload - Screenshoty hlaviček - Běžně používané časy

Útoky man-in-the-middle

Nějaký zlý provozovatel části sítě, přes kterou putuje komunikace, může uživateli podvrhnout stránku se svým obsahem ze svého serveru. (Stačí, když třeba podvrhne DNS záznam nějakého serveru a nasměruje ho někam k sobě.) Aby to útočník neměl tak snadné, zavádějí servery poslední dobou komunikaci po https. Https komunikaci s platnými certifikáty nejde podvrhnout, takže si uživatel může být jistý, že skutečně načítá obsah ze správného serveru. (Kdyby se totiž https načítalo z útočníkova serveru, nahlásí to chybu certifikátu. Útočník si totiž nemůže na svůj server pořídit cizí platný certifikát. Stránka se špatným certifikátem začne křičet a nezobrazí se. To je super.)

Slabina je v tom, že uživatel často neví, že by měl https vyžadovat. Do prohlížeče zadává pouze adresu www.example.com, což prohlížeče vyhodnotí jako http požadavek http://www.example.com, nikoli jako https požadavek. Útočník čekající na síti pak může vesele uživateli podstrčit svou podvodnou stránku na http, která se bude uživateli zobrazovat na správné http adrese.

HSTS vynutí https

Kvůli tomuto problému vzniklo HSTS. Říká prohlížeči, že má na daném serveru vždy vyžadovat https verzi stránek a nikdy se nespokojit s http. Je to už v názvu: "Strict Transport Security" znamená něco jako "striktně bezpečný transport". Pokud prohlížeč tedy takovou instrukci v minulosti dostal, může se útočník na síti snažit jak chce, ale prohlížeč vždycky požadavek přehodí na https. 

Jak se informace o HSTS do prohlížeče dostane? Buďto po prvním načtení nějaké https stránky s HSTS hlavičkou, kterou popíšu níže, nebo mechanismem preloadu, který vysvětlím ještě níže.

Úvodní varování

HSTS může při chybném použití úplně odstavit stránky z provozu. Pokud alespoň přibližně nechápete princip https a nevíte, co děláte, do HSTS se raději nepouštějte. HSTS totiž řekne prohlížeči, že web bude vždy přístupný jenom přes https. Jestliže z nějakého důvodu nedokážete https udržet v provozu (třeba se neobnoví certifikát), uživatelé se na stránky vůbec nedostanou. Když budete potřebovat použít protokol http, nepůjde to.

Doporučuji proto při testování zpočátku používat velmi krátké časy u max-age a do instrukce preload se pustit až ve chvíli, kdy budete mít s HSTS jistou zkušenost.

Podoba HSTS hlavičky

Strict-Transport-Security: max-age=31536000

Hlavička se skládá z názvu hlavičky (Strict-Transport-Security) a z hodnoty. Max-age s počtem sekund. Číslo 31536000 je čas v sekundách, po který je následně hlavička platná. V tomto případě 1 rok.

Aby hlavička platila i pro subdomény, a tak se na ně nebylo možné napojit přes nešifrované http, přidává se za hlavičku ještě řetězec includeSubDomains (na velikosti písmen nezáleží):

Strict-Transport-Security: max-age=31536000; includeSubDomains

Případně ještě může přibýt řetězec preload, ale nepoužívejte ho bez rozmyslu:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Preload způsobí, že se informace o HSTS na webu dostane přímo do nového prohlížeče. O tom níže.

Jak HSTS funguje

Jakmile prohlížeč uvidí na webu hlavičku Strict-Transport-Security, poznamená si, že dokud neuplyne max-age, na tento web nesmí přistoupit přes http. Kdyby uživatel chtěl otevřít stránku na http, stránka nevrátí kód 200 s obsahem stránky, ale vždy vrátí přesměrování na https verzi. Ve skutečnosti při tom dokonce prohlížeč vůbec nekontaktuje server a přesměrování si zařídí úplně sám. (Http kód přesměrování je v takovém případě 307 Internal redirect.)

Max-age, tedy platnost v sekundách, se nastavuje vždy znovu. Je-li nastaven jeden rok, bude platit jeden rok od poslední návštěvy. Pokud se uživatel vrátí, znovu se mu nastaví rok.

Pokud potřebujete platnost HSTS zkrátit nebo zrušit, nastavte menší čas nebo rovnou nulu. Pamatujte ale, že uživatelé, kteří navštívili stránku v době, kdy měla HSTS větší max-age, v prohlížeči tuto dobu mají stále uloženou a jejich prohlížeč bude odmítat zobrazit obsah na http verzi, dokud si nenačte https stránku s novým nastavením hlavičky.

HSTS hlavičku nejde přenastavit nezabezpečeným http protokolem. Prohlížeč ji akceptuje jedině přes https. To zcela dává smysl, protože zrušení HSTS by bylo to první, co by útočník přes http udělal, kdyby to šlo. Pokud se HSTS hlavička pošle přes http, prohlížeč ji ignoruje.

Je lhostejno, jaká stránka vyvolá uložení HSTS hlavičky. Každá stránka webu (přesněji každá cesta, takže i obrázek nebo skript) má právo nastavit HSTS. Nemusí to být hlavní stránka. Ovšem stránka ze subdomény nemá právo nastavit HSTS pro hlavní doménu.

Podpora v prohlížečích

Velmi slušná. HSTS podporují všechny dnešní prohlížeče (2017). Internet Explorer 8, 9 a 10 HSTS neumí, ale tyhle prohlížeče už jsou dnes velmi vzácné. (Prohlížeče se mohou lišit v tom, jestli dovolí uživateli přístup na https stránky, které mají rozbitý nebo podvržený certifikát. Konkrétně prohlížeč Edge mě tam s obrovským varováním pustí, Chrome ne. Ale to se přímo netýká HSTS.)

Pamatujte, že na HSTS nemusejí brát ohled různé utility nebo třeba roboti vyhledávačů. Fungující HSTS by tedy nemělo nahrazovat správné přesměrování na https verzi, pouze ho doplňuje.

Nastavení HSTS pomocí .htaccess

Ještě než budete cokoli nastavovat, ujistěte se, že stránky běží na https, to je nutná podmínka. Pro přechod stránek na https jsem napsal dost obsáhlý návod. Také pokud nevíte, co je .htaccess, napřed si ho vyzkoušejte na lehčích úkolech.

Chci-li na doméně zapnout HSTS na jeden rok, do .htaccess napíšu:

Header set Strict-Transport-Security "max-age=31536000"

To způsobí, že server pošle prohlížeči hlavičku v podobě zmíněné výše, totiž

Strict-Transport-Security: max-age=31536000

Případně můžu do .htaccess napsat:

Header set Strict-Transport-Security "max-age=31536000; includeSubdomains"

nebo dokonce

Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"

Header set je klíčová fráze používaná v mod_headers pro přidávání hlaviček. Modul serveru mod_headers bývá zapnut na většině serverů Apache.

V předchozím příkladu jsem použil zápis Header always set..., což znamená, že se hlavička přidá i k přesměrováním. To bude důležité, až bude řeč o subdoménách. (Sice se hlavička takto přidá i k přesměrovaným požadavkům na http, ale to bude prohlížeč ignorovat.)

Pokud máte na serveru jiný webserver než Apache, takže nemůžete použít .htaccess, najděte si prosím zapínání HSTS v jiných zdrojích podle konkrétního serveru. Například na serveru nginx se v souboru nginx.conf musí použít příkaz add_header, syntaxe je podobná. Možná to ale bude muset udělat administrátor serveru.

IncludeSubDomains

Relativně jednoduchá instrukce IncludeSubDomains, přidaná do http hlavičky, způsobí, že se bude napříště https vynucovat také na všech subdoménách.

Na všech subdoménách? Na jakých všech?

Na těch, které jsou subdoménou pro doménu, na kterou se právě prohlížeč ptá. Takže při použití InclueSubDomains například na doméně ahoj.example.com se bude napříště https vynucovat jak na doméně ahoj.example.com, tak na cokoliv.ahoj.example.com. Ale už ne na www.example.com nebo example.com. Aby se HSTS nastavilo na všech subdoménách webu, musí být nastaveno pro example.com.

www je subdoména!

To mi trochu komplikuje život, protože já typicky požadavky na svoje stránky přesměrovávám na subdoménu www (domnívám se, že to uživatelé mají raději). Pokud ale nastavím HSTS jen na subdoméně www.example.com, přidání includeSubDomains mi je houby platné, protože se nebude vztahovat na  http://example.com bez www. Což je ale adresa, na kterou může někdo útočit.

Řešením je tedy buďto nějak vynutit požadavek na https://example.com (a zároveň nastavovat hlavičku s "always", aby se přidala i k přesměrování), nebo se spolehnout na mechanismus zvaný preload, který popisuji níže. I pak ale musím dělat přesměrování dvě. Napřed z http://example.com přesměrovat na https://example.com (na kterém můžu nastavit hlavičku s includesubdomains) a teprve potom přesměrovat na https://www.example.com. Správné chování HSTS pro celou doménu se všemi subdoménami není možné jinak udělat (pokud se mýlím, dejte mi prosím vědět). Dvojí přesměrování mě mrzelo, ale pak jsem si uvědomil, že to první přesměrování je v normálním případě bleskurychlé, protože ho přes kód 307 udělá sám prohlížeč bez toho, aniž by se serveru musel na cokoli ptát. HSTS přesně takhle funguje: mění http na https bez ptaní.

Preload

Výše popsané HSTS jako ochrana funguje dobře, když uživatel web napřed navštíví.  Co když ale jde na web poprvé a hned je vystaven útoku - ani prohlížeč, ani uživatel ještě nevědí, že web běží přes https a na webu je HSTS. Tehdy by se útok podstrčením http verze mohl zdařit. Kvůli tomu existuje mechanismus preload.

Preload způsobí, že si web s nastaveným HSTS do své databáze zahrne Chromium a umožní výrobcům prohlížečů zakompilovat informaci o HSTS webu přímo do aktualizací prohlížečů. Prohlížeč tedy od začátku ví, že na některé weby nesmí přes http.

Funguje to, když:

Takže třeba

Strict-Transport-Security: max-age=10886400; includeSubDomains; preload

Pak můžete přejít na stránku https://hstspreload.org/, což je autoritativní stránka projektu sběru domén s HSTS a vytváření jejich seznamu. Umožňuje i ověření, jestli na seznamu určitý web už je zahrnutý, nebo není. Formulář zejména umí říct, co brání uvedení webu do seznamu, takže se lze hodně poučit, co může být kde špatně. Pokud formulář hlásí chybu, ještě to neznamená, že HSTS funguje špatně. Některé chybové hlášky pouze znamenají, že nebude fungovat preload, i když HSTS je nastavené správně.

Pokud nic nebrání preloadu, formulář přejde do druhého kroku, ve kterém majitel webu potvrdí, že se web má přidat do seznamu domén s HSTS preloadem. Formulář doporučuji používat i v případě, že do toho seznamu nechcete -- otestuje to základní chyby.

Chromium pravidelně poskytuje výrobcům prohlížečů tento seznam webů (říkají mu HSTS preload list), které jedou na HSTS. Výrobci prohlížečů to kompilují do binárek a aktualizací svých prohlížečů. Tak se informace o HSTS dostane i k uživatelům, kteří na konkrétní web nikdy nemuseli přijít. Hned od začátku je znemožněno poskytování obsahu na http.

Doporučuji velkou opatrnost při nastavování HSTS s preload, protože weby je snadné do seznamu přidat, ale velmi těžké odebrat. Také už se na nich potom nedá chování HSTS testovat.

Ještě screenshoty hlaviček

Běžné přesměrování na https, ale napřed bez HSTS. Odpověď z http protokolu o HSTS ještě nic neví:

Nastavil jsem HSTS. Odpověď od https stránky s nastavenou HSTS:

Takhle to vypadá, když se potom pokouším přistoupit na http verzi poté, kdy už platí hlavička HSTS. Všimněte si, že je tam stavový kód 307 internal redirect. Prohlížeč tedy s http vůbec nekomunikuje, rovnou požadavek povýší na https a serveru se přes http na nic neptá.

Screenshoty vyříznuty z Web inspektoru (F12, Chrome, karta Netvork, klik na objekt).

Obrázek úspěšného vložení webu (testoval jsem to na portugalsko.net) do formuláře na hstspreload.org:

Následující dvě chyby mi daly zabrat nejvíc. Jde o to, že hstspreload.org kontroluje HSTS hlavičku pouze na hlavní doméně example.com (v tomto případě gruzie.com), kterou já ale nepoužívám a rovnou ji přesměrovávám na subdoménu www a https. Do budoucna budu muset weby napřed přesměrovávat na https verzi (to pak díky HSTS zařídí prohlížeč) a teprve potom na www.

Běžně používané časy max-age

10886400 sekund je 18 týdnů. Jde o minimální dobu, kterou je nutno nastavit, aby zafungoval preload. (Podmínka nutná, nikoli dostačující.)

31536000 sekund je 1 rok, konkrétně 365 dnů.

Já rád z hlavy nastavuji 15 miliónů, tedy 15000000. Je to necelý půlrok a dobře se mi to pamatuje.

7776000 sekund jsou 3 měsíce.

24192000 sekund je 40 týdnů, počítá se od poslední menstruace.

300 sekund je 5 minut. Rád tuto hodnotu používám na testování. Je to doba, za kterou se stačí něco otestovat a naopak je dost krátká, pokud se musí počkat, až uplyne.

Publikováno 5. 5. 2017

 

Reklama

www.webhosting-c4.cz, extra rychlý SSD webhosting s doménou v ceně
o tvorbě, údržbě a zlepšování internetových stránek

Návody HTML CSS JavaScript Články Ostatní

Encyklopedie FrontPage Reklama PHP Server

Jak psát web píše Yuhů, Dušan Janovský. Kontakt.