Bezpečnost 3. – Obecná doporučení

Ve dvou předchozích částech jsme si ukázali, že keychain není zase tak bezpečný jak se mnozí domnívají. A také to, že pouhé použití HTTPS nás nezachrání. Aplikace si myslí jak bezpečně komunikuje, ale opak může být pravdou. Co dál? Jak to správně navrhnout a naprogramovat?

Náš cíl

Cílem celé série bude návrh a implementace aplikace (včetně API pro server), která bude obsahovat následující funkcionalitu:

  • přihlašování pomocí jména, hesla,
  • zamykání, odemykání pomocí PINu, který bude stačit k následnému přihlášení bez nutnosti znovu zadávat jméno / heslo,
  • omezený počet pokusů na odemčení aplikace,
  • zamykání při nečinnosti (= nutné znovu zadat PIN),
  • lokální ukládání citlivých dat,
  • obrana proti útokům.

Na první pohled nic složitého. Ale než se pustíme do samotného programování, projdeme si pár doporučení.

Citlivá data šifrujeme

Citlivá data neukládáme v čitelné formě (plaintext). A to ani do keychainu. Za všech okolností je šifrujeme.

Klíč, který používáme na šifrování, dešifrování, by neměl být součástí aplikace. Pokud je to možné, klíč by měl poskytovat server a to až po řádném ověření uživatele.

Minimalizujeme použití Objective-C

Objective-C je hacker friendly a nic na tom nezměníme. To je prostý fakt. Veškerý kód, který se týká bezpečnosti, by měl být napsán v čistém C, případně ASM. To netrpí neduhy jako Objective-C a existují techniky, které práci útočníkům znesnadňují. Nejen jim, ale i škodlivým aplikacím sbírající informace.

Pokud už to musí být Objective-C, pojmenujte metody a třídy jinak. Na první pohled by nemělo být zřejmé, že jde o kód řešící bezpečnost. Grep (a class-dump, …) velmi rychle najde metodu +(BOOL)isDeviceJailbroken. A jak sami už víte, je otázkou chvíle zajistit aby vracela YES.

Nepoužíváme Objective-C třídy (NSString, …) na držení citlivých informací v paměti. Musíme si napsat vlastní řešení v čistém C. Cílem je absolutní kontrola nad referencema, alokací, přepisem a uvolněním. Toho nelze v Objective-C snadno dosáhnout.

Obfuskace

Obfuskujeme nejenom metody tříd, názvy tříd, ale i data uložená v aplikaci. Vše, co by mohlo útočníka zajímat. Existuje velmi málo nástrojů na automatickou obfuskaci Objective-C a proto si to musíme udělat sami.

U knihoven třetích stran, například SSKeychain, měníme názvy metod. Pokud má útočník zařízení pod kontrolou, většinou jde o malware, má předpřipravený seznam tříd, jejich metod a sbírá data, která do nich posíláme. V tomto případě by ho mohlo zajímat setPassword:forService:account:.

Pokud v aplikaci detekujeme jailbreak, můžeme zobrazit varování. Řetězce, které chceme zobrazit, obfuskujeme a do čitelné podoby je převádíme těsně před použitím. V opačném případě útočníkovi sdělujeme kde probíhá detekce.

Detekce jailbreaku se provádí mnoha způsoby a jedním z nich je kontrola existujících souborů (/Applications/Cydia.app, apod.). Obfuskace se týká i těchto řetězců.

Obecně řečeno – cokoli, co by mohlo dovést útočníka ke kritickým částem aplikace, obfuskujeme. Automaticky, obfuskace by měla probíhat při sestavování výsledného produktu.

Nevěříme nikomu a sobě na 50%

Nevěříme operačnímu systému, sdíleným knihovnám a validujeme adresní prostor kritických metod před jejich použitím.

Z Objective-C známe swizzling umožňující nahrazování metod. Pro sdílené knihovny v C může útočník použít DYLD_INSERT_LIBRARIES (pokud znáte Linux, obdoba LD_PRELOAD). Dá se tak velmi jednoduše podstrčit vlastní CCCrypt a bez práce tak získat klíč na šifrování / dešifrování.

Debugger

Pokud má útočník zařízení pod kontrolou, může použít ladící nástroje – GDB, LLDB, … Aplikace by měla jejich použití znemožňovat. To je možné prolomit, ale už jsou na to potřeba změny v kernelu a nebo editace binárky aplikace. A to spolehlivě zastaví script kiddies, sledovače tutoriálů, automatiku, …

Ale i přesto by součástí aplikace měla být detekce připojení debuggeru s následným zahozením citlivých dat.

Jailbreak

Apple nenabízí spolehlivé API (nenabízí žádné), které by detekovalo jailbreak. Opět si musíme pomoc sami. Detekce probíhá mnoha způsoby a všechny si později ukážeme.

Aplikace by měla dál fungovat i na jailbreaknutém zařízení. Většina aplikací, včetně bankovních, zobrazuje varování a žádné další kroky (omezení funkcionality) nepodniká.

Vlastní funkce

Minimalizujeme použití Objective-C a vlastní bezpečnostní funkce píšeme v C. Všechny tyto funkce označujeme atributem inline. To má za následek, že tělo této funkce se vloží na všechna místa odkud je volána. Útočník tak musí chování funkce modifikovat na více místech a minimálně ho to zdrží.

Pokud si nejste jisti, že metody jsou opravdy inlinované, můžete místo toho použít makra. Což je trochu náročnější na údržbu, ale 100% jistota.

Paměť

V paměti nedržíme žádná citlivá data pokud nebyl uživatel řádně ověřen. Správu paměti pro citlivá data máme vlastní, kterou plně kontrolujeme. Při odhlášení, uzamčení, přechodu do pozadí, citlivá data zahazujeme.

Aplikace typu – načte citlivá nezašifrovaná data z disku, zobrazí je, přes to plácne modální okno vyžadující heslo, které je uloženo na disku v nezašifrované podobě – opravdu ne. Modální okno sestřelíme raz dva a nebo si data stáhneme pomocí iExplorer. Ani jailbreak není potřeba, stačí nám na pár minut připojený telefon.

Logování

Dost často se citlivé informace dostávají do systémového logu vinou špatných postupů. Programátor chce zjistit hodnotu proměnné a tak tam vrazí NSLog. To je špatně. NSLog se nedá kontrolovat. Použijte CocoaLumberJack nebo podobné knihovny. Mají různé úrovně logování, které se můžou pro každý soubor, třídu, … lišit. A pro finální produkt je možné logování globálně vypnout. Zajímá-li nás hodnota proměnné dočasně, můžeme použít breakpoint a expression, která ji pošle do logu. Nikdy tak nezůstane nedopatřením v kódu.

Závěrem

Dnes jsme si prošli pár hlavních doporučení, kterých bychom se měli držet. Berte to jako přehled, protože ke všemu se vrátíme později. Vše si detailně rozebereme včetně příkladů, implementace a útoku.

Je potřeba si nalét čistého vína – můžeme se snažit sebevíc, ale zkušený útočník prolomí všechno. Pokud si naši aplikaci vybere za cíl, dříve či později vyhraje. Proč to tedy děláme?

Malware – jailbreaknutý telefon, Cydia, Pangu, … Jak víte, co přesně si do telefonu instalujete? Vy těm zdrojům věříte? Já ne. Nehledě na fakt, že malware nepochází jenom z těchto zdrojů. Telefon vám nikdo neukradl, máte ho v ruce, převádíte peníze, přihlašujete se do různých služeb, kdo může útočit? Zkušený útočník? Malá pravděpodobnost. Většinou jde o malware, který je dost sofistikovaný, těžko odhalitelný, sbírající citlivá data a vy o něm vůbec nevíte.

Script kiddies, tutorial followers – internet je plný skriptů a návodů jak něco hacknout. Tato skupina lidí se snaží útočit na aplikace tak, že postupuje podle návodu a občas se jim to podaří. Nejsou to zkušení lidé a proto je dokáže zastavit lehká obfuskace a další techniky. Jakmile jim něco podle tutoriálu nefunguje, zabalí to.

Zkušený útočník – pokud se naše aplikace dostane do jeho hledáčku, máme smůlu. Dříve či později vše prolomí. Můžeme mu to udělat těžší, mnohem těžší a zvýšit tak šance, že ho to přestane bavit. K tomu správně navržené API serveru, komunikace, … a ve výsledku mu to nemusí přinést žádný užitek.

Tomu všemu se musíme bránit. Spolu s popularitou iOS roste i počet útoků a pravděpodobnost, že to na vaši aplikaci někdo zkusí.

Možná jsem paranoik, ale prasklinka sem, prasklinka tam a je tu povodeň. Nevěřte nikomu, ničemu a sobě na padesát procent.

V příští části si vytvoříme kostru aplikace. Začneme s detekcí jailbreaku a obfuskací. Připravím k tomu projekt, který bude na GitHubu. Volně ke stažení se všemi materiály.