Bezpečnost. To je něco, co často chybí. Takže jak to je tady?
Snadno si můžeme představit paranoidní a neprůstřelné zabezpečení… ale stojí strašně moc zdrojů, což na mikrokontroléru nechceme. Takže vždy musí jít o kompromis. Jak to je zde?
Mikrokontrolér
Zabezpečení koncového zařízení počítá s tím, že jde o krabičku, která běží někde v terénu. Nechceme, aby případný útočník, který se k ní dostane, snadno získal hesla k WiFi nebo k serverovému řešení. A samozřejmě nechceme, aby si mohl číst data, která tečou přes síť.
Pokud útočník jen přepne zařízení do konfiguračního portálu, musí se nejprve přihlásit k WiFi AP. To má samozřejmě heslo, které je možné si pro svou aplikaci nastavit na nějakou nezvyklou hodnotu. A i když už se útočník přihlásí k WiFi, v konfiguračním portálu uvidí běžná nastavení, ale ne hesla. Ta se musí zadávat pokaždé znovu, konfigurační portál je nezobrazuje ani v „hvězdičkované“ formě.
Představme si útočníka trochu vyspělejšího. Připojí krabičku k počítači a nahraje do ní aplikaci, která vypíše všechny soubory na filesystému. Tedy i konfiguraci. Hesla neuvidí, protože všechna hesla jsou při ukládání automaticky šifrována.
- Použitá šifra je AES-256-CBC.
- Klíč se derivuje (SHA256) z hesla, které je hardcodované v aplikaci, a z ID procesoru (= v každém mikrokontroléru je jiný).
- Inicializační vektor se derivuje ze jména položky (= i stejný obsah bude mít pro každou šifrovanou položku jiný výsledek v souboru).
- Pokud tedy útočník nahrál aplikaci pro výpis souborů, přišel o šifrovací klíč.
- Pokud však útočník zná cestu jak vydumpovat celou flash paměť, a dokáže analyzovat kód alespoň natolik, aby našel heslo, může se ke konfiguraci dostat. Ano, pro šifrování by šlo použít eFuses, ale deployment by se natolik zesložitil, že to pro mé low-profile aplikace nestojí za to. Ideální je tedy heslo mít ne jako konstantu, ale skládat ho aplikačně z více částí.
Komunikace
Pojďme o úroveň výš – útočník má pod kontrolou WiFi nebo spojovou cestu. Co uvidí?
Není použito https. Důvody jsou následující:
- Udělat https příčetně, s verifikací chainu, je na hranicích schopností ESP8266 – jde to, ale zabírá to strašně moc paměti. A bez verifikace chainu to nemá smysl.
- Je poměrně složité zajistit, aby to fungovalo s několikaletým výhledem dopředu. V takovém případě je potřeba zajistit distribuci klíčenky s důvěryhodnými root certifikáty na zařízení – protože důvěryhodné autority se budou měnit. Viz letošní na poslední chvíli vyřešený problém s novým rootem letsencrypt a jeho podporou na starých Androidech. Snadno se může stát, že aplikace prostě chain za pár let nedokáže ověřit. Nebo že nebude schopná se prostou změnou konfigurace přesměrovat na jiný server – protože ten bude mít jiný cert chain.
Tedy jsme o úroveň níže – prosté http. Nicméně přenášená data jsou šifrovaná (AES-256-CBC) šifrovacím klíčem, který se každý den mění (session klíč). Získání session klíče probíhá pomocí ECDH:
- zařízení si vygeneruje ECDH privátní a veřejný klíč
- veřejný klíč zašifruje AES-256-CBC pomocí klíče odvozeného SHA256 z passphrase zařízení (kterou má k dispozici zařízení i server) a výsledek pošle na server
- server si vygeneruje ECDH privátní a veřejný klíč
- veřejný klíč zašifruje AES-256-CBC pomocí klíče odvozeného SHA256 z passphrase zařízení a výsledek vrátí zařízení
- obě strany si pak pomocí svého privátního klíče a veřejného klíče protistrany vygenerují sdílený ECDH secret, z něj se pomocí SHA256 vyderivuje session klíč.
Pomocí passphrase zařízení se tak šifruje pouze a jen veřejný klíč zařízení a serveru – nešifrují se s ním jakákoli formátovaná data, ani se neposílá přes síť v jakékoli jiné formě. Není tedy možné snadno bruteforcovat passphrase pomocí jednoho odchyceného přihlašovacího paketu – nelze snadno ověřit, že dešifrovaná data jsou validní.
(Přesněji:
1) Lze rozlišit, zda dešifrováním paketu vznikl platný ECDH veřejný klíč. Pokud tedy budete mít jednoduchou passphrasi zařízení, může se to útočníkovi podařit bruteforcnout. Kolizí, kdy decode( data, sha256(kandidátská passphrase)) je platný ECDH veřejný klíč, je hodně a nelze lokálně rozlišit, která je ta správná. Ale pokud útočník odchytí více přihlašovacích paketů, může pomocí nich ověřit, zda kandidátská passphrase je ta správná (vede k platnému ECDH veřejnému klíči ve všech případech).
2) Passphrase zařízení by tedy neměla být příliš jednoduchá. Čím delší text, tím lepší. Alespoň 16 znaků.
3) Získá-li útočník passphrase, může se impersonovat jako vaše zařízení. Nemůže ale zjistit obsah zasílaných dat z vašeho regulérního zařízení – tím, že se session klíč generuje přes ECDH, nelze ho (jen) z přenášených údajů snadno získat.
4) Pokud by útočník získal passphrase, a přihlásil by se jako vaše zařízení, dojde k situaci, že bude kolidovat jeho session a session regulérního zařízení – útočník svým přihlášením odpojí session vašeho zařízení; to se opět přihlásí a tím odpojí session útočníka a takhle se to bude opakovat stále dokola. Tím je možné situaci detekovat. )
Session klíč se ukládá do RTCMEM, takže se zařízení nemusí znovu přihlašovat, i když mezi požadavky spí v deep sleepu. Denní výměnu session klíče si vynucuje server, není závislá na času v zařízení.
Pod čarou: Někdo se zeptá, proč není použito MQTT(S) či jiný podobný IoT-friendly protokol. Jeden z bodů zadání zněl „snadný provoz na nějakém levném hostingu“. Webserver s PHP je k dispozici za pár korun – a umí jen http a https. MQTT(S) už znamená virtual server za více peněz a hlavně s výrazně náročnější správou a údržbou.
Server
Hesla uživatelů aplikace jsou v uložena v databázi ve formě bcrypt hashů. Aplikace je připravená na jejich přehashování pro budoucí zvýšení ceny hashování/algoritmu, tj. prostou změnou konfigurace se při následných přihlášeních zlepší kvalita použitého hashe.
- Při opakovaném chybném zadání hesla se účet dočasně zamyká – v režimu exponential backoff, tj. první chyby si ani nevšimnete, ale při každé další budete muset čekat déle a déle, než vám to dovolí zkusit přihlášení znovu.
- Aplikace si eviduje informace o úspěšném i neúspěšném přihlášení (IP adresa, user agent) a po přihlášení je vypisuje uživateli, aby měl přehled.
Hesla zařízení nemohou být uložena jako hashe, protože
- se z nich derivuje klíč pro úvodní výměnu veřejných klíčů,
- se ukazují uživateli, aby věděl, co do zařízení nastavit.
Jsou uloženy šifrovaně (AES-256-CBC). Klíč pro šifrování se derivuje (SHA256) z master passphrase zadané v konfiguraci webovky.
Pokud tedy přijdete o dump databáze (nebo se útočníkovi podaří do DB nahlédnout jinak), není vše ztraceno, pokud útočník zároveň nezíská i konfigurační soubor webovky. Pokud však má obojí, má tím k dispozici hesla zařízení. Ne však hesla uživatelů.
Aplikace loguje do několika rotovaných log souborů. Z pohledu bezpečnosti je zajímavý zejména auditní log, kde se evidují jednotlivá přihlášení a bezpečnostně citlivé akce, např. mazání záznamů.
Všechny díly: