Beitragsbild Ziegler AriasNachdem Sie im ersten Teil unseres Beitrags die grundlegenden Sicherheitskonzepte von iOS kennen gelernt haben, wollen wir in diesem Teil verstärkt auf den Entwickleralltag eingehen und einen etwas praktischeren Blick auf die Sicherheit von Apps unter iOS werfen.

Neben den in der Sprache Swift enthaltenen, sicherheitssteigernden Sprachfeatures betrachten wir vor allem Authentifizierungsprozesse und die sichere Speicherung von Daten.

 

Wer sind die Angreifer

Egal ob im Việt Cộng dem Gaza-Konflikt, in Nordirland, während der Inquisition oder auf dem Kinderspielplatz, die Welt wäre stets einfacher (gewesen), wenn Menschen zu jeder Zeit darüber Bescheid wüssten, wer ihre Kontrahenten sind. Leider kann man die Welt nicht ohne weiteres nach dem Schneewittchen-Prinzip in Gut und Böse einteilen. Das ist in der IT-Sicherheit heutzutage nicht anders; besonders im Hinblick auf mobile Endgeräte ergeben sich völlig neue Angriffsszenarien. Ein Beispiel dafür ist Diebstahl, der bei Smartphones denkbar leicht vonstattengeht. Auch die Manipulation eines Mobiltelefons ist heute in sehr kurzer Zeit möglich, sodass ein Angreifer in der Lage dazu ist, das Gerät unbemerkt zu entwenden, Schadsoftware aufzuspielen oder Daten zu stehlen und anschließend wieder an ursprünglicher Stelle auftauchen zu lassen.

Um Ihnen einen Eindruck davon zu vermitteln, wer Ihren Nutzern und deren Geräten gefährlich werden kann, haben wir hier einen kurzen Überblick zusammengestellt[1]:

 

  • Staaten und Geheimdienste
  • Unternehmen
  • Eifersüchtige Lebensabschnittsgefährten
  • Neugierige Bekannte
  • Kampfdrohnen

In Abhängigkeit von Identität und Ziel des Angreifers ergeben sich unterschiedliche Angriffsszenarien.

Ein wohl allgemeingültiges Angriffsszenario sind unsichere Kommunikationswege. Dabei nutzt ein Angreifer die Tatsache, dass Kommunikation unverschlüsselt oder unzureichend verschlüsselt und authentifiziert stattfindet. Er hat so die Möglichkeit, unter anderem sogenannte Man-in-the-Middle-Angriffe und Spoofing-Attacken durchzuführen. Das betrifft sowohl Smartphones, als auch andere Geräte, die auf traditionellem Weg mit dem Internet verbunden sind. Bei mobilen Geräten allerdings, gibt es zusätzliche Möglichkeiten für die Angreifer. So können sie sich unter bestimmten Umständen beispielsweise als Netzbetreiber ausgeben[2].

 

Typsicherheit in der Sprache Swift

Apples neue Sprache Swift ist der Versuch, Entwicklern ein zeitgemäßeres Werkzeug an die Hand zu liefern. Swift beinhaltet dabei Sprachfeatures, die eigentlich seit den 70er-Jahren bekannt sind, sich aber im “Mainstream” (oder “bei den coolen Kids”) bisher nicht durchgesetzt hatten.

Chris Lattner, der Erfinder der Sprache, listet auf seiner persönlichen Homepage unter anderem die Sprachen Objective-C, Rust und Haskell als Vorlagen für Swift (Lattner, 2014). Während es sich bei Haskell um eine seit Jahren bekannte und beliebte funktionale Programmiersprache[3] handelt, ist Rust ein Projekt von Mozilla, das kurz vor Swift mit ungefähr dem gleichen Ziel gestartet wurde: eine typ- und speichersichere, moderne Sprache zu entwickeln, die Konzepte aus funktionaler Programmierung übernimmt, aber dennoch nah genug an verbreiteten Sprachen liegt, um in der breiten Masse Akzeptanz zu finden. Diese Herangehensweise scheint sich auszuzahlen. Rust und Swift sind (in den entsprechenden Communities) in aller Munde.

Eines der Merkmale von Swift, auf das wir hier ganz speziell eingehen wollen, ist die Typsicherheit. Dieser Begriff sollte vielen Entwicklern bekannt sein. Wenn Sie noch nie von Typsicherheit gehört haben, so kennen Sie sicher zumindest die Folgen von mangelnder ebensolcher. Typsicherheit verhindert eine bestimmte Art Fehler, der auftritt, wenn Objekte oder Variablen zur Laufzeit einen anderen Typ haben, als das Programm an einer bestimmten Stelle von ihnen erwartet. Also wenn beispielsweise eine Methode auf einem Objekt aufgerufen (oder eine Nachricht an ein Objekt gesendet) wird, welche von der entsprechenden Klasse gar nicht bereitgestellt wird. Der Objective-C-Compiler warnt bei solchen Problemen nur eingeschränkt, nämlich dann, wenn er sicher sagen kann, dass eine Methode nicht implementiert wird. Häufig kann zur Compilezeit aber nur festgestellt werden, dass es möglich wäre, dass zur Laufzeit ein bestimmtes Objekt eine bestimmte Methode bereitstellt. Wenn diese Hoffnung des Compilers zur Laufzeit enttäuscht wird, wirft die Laufzeitumgebung eine Exception und bringt die App zum Absturz.

Häufig sind Sicherheitslücken in Programmen, Apps oder Betriebssystemen einer fehlerhaften Speicherverwaltung oder der Fehlinterpretation von Daten geschuldet. Klassische Exploits, wie Format-string-Exploits, Buffer overflows und double frees, basieren praktisch komplett darauf, dass Programmierer Fehler machen, wenn es die Sprache ihnen erlaubt.

Obwohl die Sprache Swift grundsätzlich typsicher ist, war der Maßstab der Typsicherheit beim Sprachdesign offenbar nicht für alle Sprachfeatures maßgeblich. So gibt es in Swift sogenannte Selektoren (selectors), die es erlauben, sogenannte callbacks für Funktionen in Form eines Strings zu spezifizieren, die dann von der Laufzeitumgebung aufgerufen werden (siehe Listing 1).

Lisiting 1: Beispiel für einen selector.

func timerCallback()
{
    //dummy function
}

NSTimer.scheduledTimerWithTimeInterval(1.0,
    target:self,
    selector:"timerCallback",
    userInfo:nil,
    repeats:true
)

Dabei muss der Prototyp der übergebenen Funktion dem erwarteten Prototyp entsprechen. Andernfalls kommt es zu einem Laufzeitfehler, der einen Programmabsturz bedingt.

Datenablage

Es ist allgemein üblich, Dateien, die von einer Anwendung benötigt oder erzeugt werden, unverschlüsselt im Dateisystem abzuspeichern und damit für jedermann, der Zugriff auf das Dateisystem hat, zugänglich zu machen. Wenngleich diese Praxis auch bei herkömmlichen Betriebssystemen nicht lupenrein ist – schließlich kann so jeder, der physikalischen Zugriff auf den Rechner hat (und oft auch andere Nutzer), auf diese Dateien zugreifen – kann man dieser Vorgehensweise dabei zumindest nicht so schwere Sicherheitsprobleme wie unter mobilen Betriebssystemen attestieren.

Mobile Endgeräte können nicht nur besonders leicht physikalisch entwendet werden, sondern häufig werden auf Ihnen auch wahllos Anwendungen beliebiger Herausgeber installiert, die bei der Speicherung ungeschützter Dateien ebenfalls Zugriff auf diese erlangen können. Mithilfe von Sandboxing versucht Apple Dateien mit gewissem Erfolg vor fremden Apps zu schützen, doch die Gefahr, dass Dateien im Falle eines Diebstahls des Gerätes vom Dieb entwendet werden könnten, bleibt.

Um Dateien davor zu schützen gibt es vier Data Protection Classes, die Sie bei der Erzeugung einer Datei festlegen können und die jeweils bestimmen, unter welchen Rahmenbedingungen auf die Datei zugegriffen werden darf (iOS Security Guide, 2015):

 

Data Protection Class Beschreibung
NSFileProtectionNone Kein besonderer Schutz der Datei.
NSFileProtectionCompleteUntilFirstUserAuthentication Auf die Datei kann erst zugegriffen werden, nachdem der Nutzer das Gerät zum ersten Mal entsperrt hat.
NSFileProtectionCompleteUnlessOpen Die Datei kann nur dann geöffnet werden, wenn das Gerät nicht gesperrt ist. Ist eine Datei jedoch noch geöffnet, wenn das Gerät gesperrt wird, ist ein Zugriff weiterhin möglich.
NSFileProtectionComplete Die Datei kann nur verwendet werden, wenn das Gerät entsperrt ist.

 

Sie sollten von diesen Data Protection Classes stets Gebrauch machen und Daten jeweils bestmöglich vor dem Zugriff Dritter schützen.

Gerade dann, wenn in Ihrer App Passwörter gespeichert sind, sollten Sie genau überlegen, unter welchen Bedingungen diese benötigt werden. Sie sollten es dabei unbedingt vermeiden, diese Passwörter ungeschützt im Arbeitsspeicher oder gar im Dateisystem abzulegen.

Authentifizierungsprozesse

Viele Anwendungen erfordern eine Authentifizierung des Nutzers gegenüber einem Server oder einem anderen Nutzer. Gerade die Authentifizierung gegenüber einem Server wird dabei sehr häufig mithilfe von Passwörtern realisiert, während eine Authentifizierung gegenüber einem anderen Nutzer oft gar nicht stattfindet.

Unter Authentifizierung versteht man die Erbringung eines Nachweises für eine behauptete Eigenschaft. Im Falle einer Authentifizierung mithilfe eines Passwortes besteht dieser Nachweis in der Kenntnis des geheimen Passwortes, das einem bestimmten Nutzer(kreis) zugeordnet ist. Ein wirksamer Authentifizierungsprozess erfordert jedoch auch einen wirksamen Schutz vor sogenannten Spoofing-Attacken, bei denen sich ein Angreifer als eine andere Person ausgibt.

Wenn im Rahmen eines Authentifizierungsprozesses also ein Passwort unverschlüsselt an den Server übertragen wird, kann sich ein Angreifer mithilfe einer Replay-Attacke, bei der er ganz einfach das übermittelte Kennwort inklusive des zugehörigen Benutzernamens selbst an den Server sendet, als entsprechender Nutzer Authentifizieren und so entweder dessen Berechtigungen oder Zugang zu dessen Daten erlangen. Aus diesem Grund müssen Authentifizierungsprozesse kryptographisch abgesichert werden. Bestenfalls wird dabei nicht einfach nur die Kommunikation zwischen Nutzer und Server beim Login mithilfe eines Passwortes durch den Einsatz von Transportverschlüsselung gesichert. Stattdessen haben Sie die Möglichkeit, Gebrauch von asymmetrischen Verfahren zu machen, bei denen das Passwort, oder, noch besser, ein echter kryptographischer Schlüssel stets auf Ihrem Gerät verbleiben und der Nachweis der entsprechenden Eigenschaft durch das Lösen einer kryptographischen Problemstellung erbracht wird.

 

Neben der Sicherheit einer App ist heute auch die Privatsphäre eine sehr wichtige Anforderung von Anwendungen. Privatsphäre können Sie heute nur noch durch den intensiven Gebrauch von kryptografischen Verfahren gewährleisten. Worauf es dabei vor allem ankommt, erfahren Sie im dritten Teil unseres Beitrages.

 

[1] Die Meinung der Autoren entspricht nicht notwendigerweise der Meinung der Herausgeber. Insbesondere entspricht auch die Meinung von Autor A nicht immer der Meinung von Autor B, wobei A,B∈{Raphael, Manuel}.

[2] Ein Beispiel für eine solche Attacke ist ein sogenannter IMSI-Catcher. Hier simuliert der Angreifer eine Funkzelle eines Netzbetreibers und gelangt so an die bestenfalls transportverschlüsselten Kommunikations- und Identitätsdaten des Nutzers (Paget, 2010).

[3] Haskell wurde in der ersten Version 1990 veröffentlicht und seither mehrfach überarbeitet. Natürlich erfreuen sich funktionale Sprachen leider nicht der Verbreitung, welche selbst drittklassig entworfene imperative Sprachen erreichen. Dies scheint sich jedoch nach und nach zu ändern. Hoffentlich. Übrigens lässt sich – entgegen einem gefühlt weit verbreiteten Vorurteil – sehr wohl sinnvolle und produktiv nutzbare Software in funktionalen Sprachen schreiben. Als Beispiel sei hier auf den window manager XMonad verwiesen (http://xmonad.org).

Literatur

(NSA: Tor Stinks, 2013) ’tor stinks’ presentation – read the full document, 2013. http://www.theguardian.com/world/interactive/2013/oct/04/tor-stinks-nsa-presentation-document.

(NSA: The king of high-secure, low-latency anonymity, 2013)         Tor: ’the king of high-secure, low-latency anonymity, 2013. http://www.theguardian.com/world/interactive/2013/oct/04/tor-high-secure-internet-anonymity.

(The Heartbleed Story, 2014) The heartbleed story, 2014. http://www.codenomicon.com/resources/brochure/pdf/Heartbleed-Story.pdf.

(iOS Security Guide, 2015)     ios security. https://www.apple.com/business/docs/iOS_Security_Guide.pdf, 2015. letzter Zugriff: 09.05. 2015.

(Callas, et al., 2007)    J. Callas, L. Donnerhacke, H. Finney, D. Shaw, and R. Thayer. RFC 4880: OpenPGP Message Format. 2007. http://tools.ietf.org/html/rfc4880.

(Dierks, et al., 2008)   T. Dierks and E. Rescorla. Rfc 5246: The transport layer security (tls) protocol version 1.2, 2008. http://tools.ietf.org/html/rfc5246.

(Dingledine, et al., 2004)        R. Dingledine, N. Mathewson, and P. Syverson. Tor: The second-generation onion router, 2004. https://svn.torproject.org/svn/projects/design-paper/tor-design.pdf.

(Goyal, et al., 2006)    V. Goyal, O. Pandey, A. Sahai, and B. Waters. Attribute-based encryption for fine-grained access control of encrypted data, 2006.

(Kerckhoffs, 1883)     A. Kerckhoffs. La cryptographie militaire. Journal des sciences militaires, IX, 1883.

(Lattner, 2014)            C. Lattner, 2014. http://chrislattner.com/.

(Paget, 2010)   C. Paget. Practical cellphone spying, 2010.

(Reed, et al., 1998)     M. G. Reed, P. F. Syverson, and D. M. Goldschlag. Anonymous connections and onion routing. IEEE Journal on Selected Areas in Communications, 16, 1998.

(Rivest, et al., 1978)    R. L. Rivest, A. Shamir, and L. M. Adleman. A method for obtaining digital signatures and public-key cryptosystems. CACM, 21(2):120–126. (This is the RSA paper.).

(Dingledine, 2013)      R. Dingledine, J. Appelbaum. Q&a marathon, 2013. https://gnunet.org/tor2013tum-video.

(Sahai, et al., 2004)     A. Sahai and B. Waters. Fuzzy identity based encryption. Cryptology ePrint Archive, Report 2004/086, 2004. http://eprint.iacr.org/.

(Zdziarski, 2012)        J. Zdziarski. Hacking and Securing iOS Applications. O’REILLY, 2012.

(Dieses Literaturverzeichnis bezieht sich auf alle drei Teile des Beitrages Sicherheit in der iOS-Entwicklung, der im kostenlosen E-Book als gesamtes Kapitel veröffentlicht wird.)