Bezpečnost 1. – Keychain

Od posledního článku uběhlo čtvrt roku a je na čase začít další seriál. Další? A co Swift? Nebojte, Swift neopouštím, k němu se ještě vrátím. Jen se snažím psát o věcech, které jsou aktuální a které zrovna sám řeším. Swift to teď není, ale je to neméně zajímavé téma – bezpečnost mobilních aplikací, resp. aplikací pro platformu iOS.

Proč toto téma? Protože si myslím, že bezpečnost je v mnoha aplikacích:

  • velmi podceňována,
  • není řešena vůbec,
  • řešena špatně.

Nečekejte detaily z kryptografie nebo popisy algoritmů. Na to tu máme kovanější odborníky – Tomáš Rosa nebo firmy jako AEC. My se na to všechno zaměříme z pohledu vývojáře – jak udělat mobilní aplikaci, která je bezpečnější v oblasti lokálního ukládání citlivých dat a komunikace se serverem. Novodobá hra kočky (hacker) s myší (vývojář).

Jaká je dnešní praxe? Většinou se programátoři spokojí s ukládáním citlivých dat do keychainu a použitím HTTPS. Je to dostatečně bezpečné? Není.

Samozřejmě, že záleží na charakteru aplikace, resp. služby. Požadavky na bezpečnost bankovní aplikace budou diametrálně odlišné od bezpečnosti aplikace na synchronizaci podcastů.

Keychain

Začneme keychainem. Úplně živě vidím následující postup:

Vůbec netuší, že každá položka může mít různé atributy a implementační detaily jsou mu skryty. Kolik vývojářů četlo dokumentaci ke keychainu nebo se podívalo do kódu SSKeychain? Mizivé procento.

Mezi nejdůležitější atributy patří kSecAttrAccessible. Ten totiž říká kdy je daná položka přístupná. Může nabývat následujících hodnot:

  • kSecAttrAccessibleAlways

Přístupná vždy a to i po restartu telefonu, který ještě nebyl odemknut.

  • kSecAttrAccessibleAfterFirstUnlock

Přístupná po prvním odemknutí telefonu po restartu. Do dalšího restartu.

  • kSecAttrAccessibleWhenUnlocked

Přístupná pouze když je telefon odemknutý.

  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly
  • kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
  • kSecAttrAccessibleAlwaysThisDeviceOnly

Platí to samé co pro výše uvedené, ale s tím rozdílem, že se tyto položky nepřenáší na další zařízení. Například při obnově dat ze zálohy. Keychain všechno šifruje a to pomocí:

  • PINu,
  • hesla,
  • kombinace výše uvedených se speciálním HW klíčem.

PIN a heslo, které používáte na odemknutí telefonu. Proto s tím iOS pořád otravuje. Speciální HW klíč se používá v případě, že atribut kSecAttrAccessible je nastaven na *ThisDeviceOnly.

Jaká je výchozí hodnota? V době iOS 4 to bylo kSecAttrAccessibleAlways. To už neplatí, dnes (iOS >= 5) to je kSecAttrAccessibleWhenUnlocked.

V jednom dílu CZPodcastu Tomáš Rosa říkal: “Velké průšvihy nejsou dílem jedné velké chyby, ale většinou jde o sled několika nešťastných událostí nebo problémů.” (není to přesná citace) A jedním z nich může být i špatná hodnota atributu kSecAttrAccessible. Nebo zapomenutý telefon, který je jailbreaknutý, odemknutý, heslo na ssh je legendární alpine, … Zkuste občas oskenovat lokální síť v kavárně kde skoro každý něco dělá na tom svém zázraku techniky. Uvidíte sami.

Dejme tomu, že máme opravdu k dispozici telefon, který je pod naší kontrolou a můžeme tak bez problémů spouštět self-signed aplikace. Dostaneme se k údajům v keychainu? Jak to funguje? Každá aplikace má přístup pouze k vlastním položkám a nebo položkám v předem definovaných skupinách. To vše schvaluje Apple. My teď Apple nepotřebujeme. Stáhneme si zdrojáky Keychain Dumper, přidáme vlastní wildcard entitlements

<key>com.apple.keystore.access-keychain-keys</key>
<true/>
<key>com.apple.keystore.device</key>
<true/>

… sami podepíšeme a hned vidíme co zašifrovaný keychain obsahuje. Co když je telefon zamknutý a k některým položkám se nedostaneme?

Zkuste se rozhlédnout kolem sebe. Je tady poměrně velká šance, že telefon ostatních lidí bude zabezpečen pomocí PINu. Řekl bych, že ta šance hraničí s jistotou. PIN má 4 cifry, to znamená 10^4 = 10.000 kombinací a to je na dnešní dobu hračka. Není nic jednoduššího než si upravit demo_bruteforce.py, chvíli počkat, odemknout telefon a získat tak přístup ke všem položkám.

Klasické heslo je tedy mnohem bezpečnější. Minimálně to bruteforce útok zpomalí nebo znemožní. To ale nejsme schopni ovlivnit. Volba uživatele = edukace.

Co z toho všeho plyne?

  • Keychain je bezpečné úložiště, ale ne za všech okolností. Očekávám nejhorší a rozhodně do něj neukládám přihlašovací údaje do banky.
  • Když chci použít keychain, musím vědět jak funguje a co všechno nabízí.
  • V oblasti bezpečnosti se snažím nepoužívat volně dostupné knihovny třetích stran. Útoky se vedou i na implementace daných knihoven.
  • Používám-li už knihovny třetích stran, a jde o bezpečnost, musím si nastudovat jejich zdrojáky a slepě na ně nespoléhat.
  • Nespoléhám na výchozí hodnoty různých atributů. Můžou se měnit.

Příště se zaměříme na HTTPS a podíváme se na komunikaci vybraných aplikací. V třetí části si specifikujeme zadání aplikace, začneme iterativně navrhovat, implementovat a budeme si to zkoušet zpětně hacknout.