7min

Soms, als ik weer eens een nieuwe app gebruik en voor de zoveelste keer wat persoonsgegevens invul, vind ik het aardig om te kijken op welke manier zo’n app ermee omgaat. Hoe worden mijn gegevens verstuurd? Hoe zit het met access control, zijn er indicatoren dat er wellicht gegevens te zien zijn die niet direct bij mijn account horen? Zien we andere zaken die erop wijzen dat er misschien… beter nagedacht kan worden over security?

Tegenwoordig is bijna alles versleuteld; dat maakt het net even wat lastiger om te achterhalen wat er nu precies gebeurt. Versleuteling vindt plaats tussen de client (app) en de server (backend), normaliter heb je dus toegang nodig tot de app of de backend om te kunnen zien wat er gebeurt. Nu kan je natuurlijk je telefoon jailbreaken, maar gelukkig zijn er ook proxy-tools als mitmproxy of Burp die kunnen helpen. Door verkeer van je smartphone door zo’n tool te leiden is vaak wel te zien wat een app doet. Mitmproxy onderschept het verkeer vanaf de app, doet alsof hijzelf de (web)server is en stuurt de (eventueel aangepaste) data vervolgens door naar de echte webserver. Het antwoord gaat op dezelfde manier terug.

Wanneer er HTTPS wordt gebruikt werkt dat niet zomaar, en dat is maar goed ook. Als ontsleuteling zo makkelijk was, zou de waarde van HTTPS een stuk kleiner zijn. In Operating systems, browsers, maar ook op smartphones bestaat een zgn. ‘Trusted Certificate Store’. Hierin staat precies wie certificaten mag ondertekenen (de Trusted Certificate Authorities – CA’s), certificaten die niet door een van die CA’s ondertekend zijn worden niet vertrouwd. Mitmproxy speelt ook CA: hij onderschept verkeer, kijkt op basis van SNI en certificate pre-fetching voor welke host er een certificaat gegenereerd moet worden, genereert deze, ondertekent deze met z’n eigen CA key en presenteert het ondertekende certificaat aan de client. De mitmproxy CA wordt echter bij het eerste gebruik gegenereerd en staat standaard niet in de ‘Trusted Certificate Store’ van de client. De verbinding mag daarom niet tot stand komen. Natuurlijk staat het je vrij te besluiten de mitmproxy CA te importeren in de ‘Trusted Certificate Store’ van je eigen client om zo toch in het verkeer te kunnen kijken, maar daarvoor moet je wel wat doen op je client (browser, smartphone) en dus werkt het alleen bij jezelf. Meestal dan – soms moet je nog door wat extra hoepeltjes springen, zoals bij pinning of TLSA.

Verificatie

Browsers checken de ondertekening van certificaten al sinds jaar en dag, het is een standaard onderdeel van security geworden. Zo standaard dat je er eigenlijk niet meer over nadenkt – bij het gebruik van een gangbare browser zal dat wel goed zitten. En alhoewel hier ook uitzonderingen op kunnen worden gemaakt (terecht – om gebruikers te beschermen, of onterecht), en bij veel van ons het Diginotar debacle nog vers in het geheugen zit, is de beveiliging van up-to-date browsers op sites met groene slotjes over het algemeen echt wel oké. En als je het wil kan je in elke gangbare browser prima achterhalen wie een certificaat heeft ondertekend (al heeft Chrome het voor de gemiddelde gebruiker wel net even iets lastiger gemaakt). Maar goed, hoe zit dat bij apps?

In het merendeel van de apps zit eigenlijk ook een soort mini-browser. Een browser die vaak maar naar 1 website kan gaan – een API naar backend van de app. Natuurlijk is het niet zo dat elke app-developer die browser helemaal zelf moet maken, in de programmeertaal waarin een app wordt geschreven (Objective C voor IOS) zit standaard functionaliteit voor het ophalen en versturen van data over HTTP(S). En standaard is dat best veilig. Een van die zaken die standaard goed wordt geregeld is checken wie certificaten heeft ondertekend en certificaten blokkeren als de ondertekenaar (de CA) niet aanwezig is in de ‘Trusted Certificate Store’. Natuurlijk kan je het als app-developer ook moedwillig minder veilig maken en alle certificaten accepteren. Misschien handig als je in de testsituatie geen zin hebt om te betalen voor een HTTPS certificaat – al is die smoes sinds enige tijd niet echt meer houdbaar vanwege de opkomst van Let’s Encrypt, waarmee je na een paar (vrij simpele, te automatiseren) stappen gratis vertrouwde HTTPS certificaten kunt krijgen. Maar goed, blijkbaar is dat nog niet makkelijk genoeg en vinden sommige developers het nog steeds nodig om al die checks maar uit te zetten.

Maar… als een app wordt gepubliceerd zal dat toch wel goed zitten? Hoe controleer je dat eigenlijk?

Terug naar de app waar ik mee bezig was. Zoals wel vaker was ik nieuwsgierig wat die app nu precies doet naar de backend. Na het verkeer van m’n iPhone te hebben omgeleid via mitmproxy start ik de app weer en beginnen de requests zichtbaar te worden in mitmproxy. Leuk – kunnen we zien wat er gebeurt. Maar toen schoot het me te binnen: “Heb ik m’n host met mitmproxy niet recentelijk opnieuw geïnstalleerd? Maar… dan heb ik de CA van mitmproxy nog niet geïmporteerd in de ‘Trusted Certificate Store’ op m’n iPhone – of wel?” Na controle bleek dat dit in inderdaad niet het geval was. Ook normale websites en andere apps geven een waarschuwing of doen het gewoon niet – maar deze app wel. Een flink beveiligingsprobleem. Het vervelendste hier is nog wel dat je dit als doorsnee gebruiker eigenlijk niet kan controleren. In browsers is dat inmiddels wel vrij duidelijk met groene balken / slotjes,  de melding ‘Veilig’ et cetera. En de rode balken en waarschuwingen als er wat mis is. Maar als een app-developer de beveiliging verlaagt en iemand luistert je af zie je daar helemaal niets van.

Later die dag heb ik de eigenaar van de betreffende App maar op de hoogte gesteld via e-mail, maar na een paar dagen heb ik nog geen reactie gekregen. Nog maar een ander e-mailadres geprobeerd – ook geen reactie. Gebeld en een bericht achter gelaten, maar ik moet nu nog steeds teruggebeld worden. Misschien nog wel frustrerender dan het beveiligingsprobleem zelf.

Wat is de potentiële impact?

Het is vaak vrij eenvoudig om op een (publiek) netwerk verkeer te onderscheppen van clients op datzelfde netwerk (met Arp spoofing). Bij clients (browsers en apps) en servers die beveiliging serieus nemen kan zo’n aanvaller dan nog niet heel erg veel: het verkeer is inmiddels versleuteld en ontsleuteling is niet zomaar mogelijk. Omdat de aanvaller niet beschikt over een ’trusted CA’ kan deze het verkeer van het slachtoffer niet proxy’en via de eerdergenoemde tools en het verkeer ontsleutelen, tenminste niet zonder dat de gebruiker dit doorheeft. Pogingen tot zo’n ‘man-in-the-middle’ aanval resulteren in waarschuwingen bij de client.

Hoe anders is dat bij apps die HTTPS beveiliging dwarsbomen door alle CA’s te accepteren. Verkeer is nu te onderscheppen en aan te passen – zonder dat de gebruiker dit doorheeft. Sta niet raar te kijken als je op een netwerk zit met andere gebruikers (publieke hotspot, of misschien zelfs een bedrijfsnetwerk), je gebruikt een app en je gegevens vallen in verkeerde handen. Of die ene transactie gaat net even naar de verkeerde persoon. Van de 42 IOS apps die ik heb getest hebben er zeker 3 dit probleem. Ook niet in de minste categorieën: een verzekeraar, een fintech app en een app in de categorie automotive (rustig… het is me nog niet gelukt auto’s te hacken). Misschien hebben wel meer van de 42 apps dit probleem, maar bij apps waarbij je in moet loggen dan in ieder geval niet op de eerste loginpagina. Goed – statistisch misschien niet significant vanwege de kleine subset, maar met 2,2 miljoen apps in de Apple App store zijn er vast en zeker een stuk meer apps die dit probleem hebben. En ook Android is niet gevrijwaard: 1 van de 3 apps die op IOS last hebben van dit probleem, heeft dat ook op Android. En van de overige 39 kan het best zo zijn dat er een paar tussen zitten die zich onder IOS goed gedragen, maar op Android niet. Conclusie: ook op Android heeft de gebruiker geen enkele garantie.

En nu?

Ik ben zeker niet de eerste die treurig wordt van de beveiliging van veel apps, ook dit specifieke probleem is al eerder ontdekt. Tien jaar na de introductie van de iPhone zien we duidelijk dat het echt een stuk beter moet. Daar waar de eigenaar van een website er direct belang bij heeft om de versleuteling enigszins veilig te houden (gebruikers houden niet van waarschuwingen en rode balken), zit dit totaal anders bij apps. Gebruikers zien het toch niet en het is lastig te achterhalen. Anders dan bij een reguliere site komen deze mankementen bij functionele tests ook niet naar voren: de testgebruikers zien het ook niet. Tijd voor de Apples en Googles van deze wereld om wat strenger te worden. Wat mij betreft halen ze de optie tot het moedwillig onveilig maken van verbindingen weg zodat developers dit niet meer kunnen gebruiken zonder actie van de gebruiker, net zoals bij browsers. Als er een verbinding wordt opgezet met een onveilig certificaat (wat doorgaans het geval is als iemand je gegevens probeert te stelen), zou dat altijd een waarschuwing moeten genereren of compleet moeten worden geblokeerd. Als je de waarschuwing wegklikt misschien een rode balk van een paar pixels hoog. Maar ja – is dat voldoende? Security is niet binary: het staat niet uit of aan. Als aan nieuws-app met publieke informatie qua security net door de beugel kan en een internetbankieren-app past hetzelfde niveau van beveiliging toe, is het dan ook goed? Hoe kunnen (de wat meer technische) gebruikers makkelijk zien welke beveiligingsmaatregelen er allemaal zijn of ontbreken (TLS versie, Cipher strength, HSTS, DNSSEC, TLSA, …)? Moet die info achter een door Apple en Google gemaakt ‘slotje’?

Tot slot een oproep: Denk na over ‘responsible disclosure’ en vermeld duidelijk op je site bij wie mensen kunnen aankloppen als ze een beveiligingsprobleem hebben gevonden. En doe daar dan ook wat mee.

Deze blog is ingezonden door Marc Guardiola, Lead Architect bij Solvinity.