Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Security

Sichere Codierung in Swift 4

by
Read Time:14 minsLanguages:

German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)

Swift ist eine großartige Sprache für die sichere Entwicklung, von der Minimierung der Zeigerverwendung bis hin zur starken Typprüfung beim Kompilieren. Das heißt aber, es ist verlockend, die Sicherheit ganz zu vergessen. Es gibt immer noch Schwachstellen, und Swift lockt auch neue Entwickler an, die noch nichts über Sicherheit gelernt haben.

Dieses Tutorial ist eine Anleitung zur sicheren Codierung, in der Änderungen in Swift 4 sowie die neuen Tooloptionen in Xcode 9 behandelt werden, mit denen Sie Sicherheitslücken verringern können.

Zeiger und Überläufe

Viele Sicherheitslücken haben sich um C und die Verwendung von Zeigern gedreht. Dies liegt daran, dass Sie mit Zeigern auf unformatierte Speicherorte zugreifen können, wodurch das Lesen und Schreiben in den falschen Bereich erleichtert wird. Es war eine wichtige Möglichkeit für Angreifer, ein Programm böswillig zu ändern.

Swift verzichtet größtenteils auf Zeiger, ermöglicht Ihnen jedoch weiterhin die Schnittstelle zu C. Viele APIs, einschließlich der gesamten Core Foundation-API von Apple, basieren vollständig auf C, sodass es sehr einfach ist, die Verwendung von Zeigern wieder in Swift einzuführen.

Glücklicherweise hat Apple die Zeigertypen entsprechend benannt: UnsafePointer<T>, UnsafeRawPointer<T>, UnsafeBufferPointer<T> und UnsafeRawBufferPointer. Es wird eine Zeit kommen, in der die API, mit der Sie eine Schnittstelle herstellen, diese Typen zurückgibt, und die Hauptregel bei ihrer Verwendung lautet, keine Zeiger für die spätere Verwendung zu speichern oder zurückzugeben. Zum Beispiel:

Da wir außerhalb des Verschlusses auf den Zeiger zugegriffen haben, wissen wir nicht genau, ob der Zeiger noch auf den erwarteten Speicherinhalt zeigt. Die sichere Möglichkeit, den Zeiger in diesem Beispiel zu verwenden, besteht darin, ihn zusammen mit der print-Anweisung innerhalb des Abschlusses zu belassen.

Zeiger auf Strings und Arrays haben ebenfalls keine Begrenzungsprüfung. Dies bedeutet, dass es einfach ist, einen unsicheren Zeiger auf ein Array zu verwenden, aber versehentlich über seine Grenze hinaus zuzugreifen - ein Pufferüberlauf.

Die gute Nachricht ist, dass Swift 4 versucht, die App zum Absturz zu bringen, anstatt mit dem so genannten undefinierten Verhalten fortzufahren. Wir wissen nicht, auf welchen buffer[5] zeigt! Swift wird jedoch nicht jeden Fall erfassen. Setzen Sie nach dem folgenden Code einen Haltepunkt und sehen Sie sich die Variablen a und c an. Sie werden auf 999 gesetzt.

Dies zeigt einen Stapelüberlauf, da Variablen ohne explizite Zuordnung im Allgemeinen auf dem Stapel gespeichert werden.

Im nächsten Beispiel nehmen wir eine Zuordnung mit einer Kapazität von nur einem Int8 vor. Zuordnungen werden auf dem Heap gespeichert, sodass die nächste Zeile den Heap überläuft. In diesem Beispiel warnt Xcode Sie nur mit einem Hinweis in der Konsole, gets der unsicher ist.

Was ist der beste Weg, um Überläufe zu vermeiden? Bei der Schnittstelle mit C ist es äußerst wichtig, die Grenzen des Eingangs zu überprüfen, um sicherzustellen, dass er innerhalb des Bereichs liegt.

Sie denken vielleicht, dass es ziemlich schwierig ist, sich an all die verschiedenen Fälle zu erinnern und sie zu finden. Um Ihnen zu helfen, wird Xcode mit einem sehr nützlichen Tool namens Address Sanitizer geliefert.

Address Sanitizer wurde in Xcode 9 verbessert. Es ist ein Tool, mit dem Sie ungültigen Speicherzugriff abfangen können, wie in den Beispielen, die wir gerade gesehen haben. Wenn Sie mit den Unsafe* -Typen arbeiten, empfiehlt es sich, das Address Sanitizer-Tool zu verwenden. Es ist standardmäßig nicht aktiviert. Um es zu aktivieren, gehen Sie zu Produkt > Schema > Schema bearbeiten > Diagnose und aktivieren Sie Address Sanitizer. In Xcode 9 gibt es eine neue Unteroption: Verwendung des Stapels nach Rückkehr erkennen. Diese neue Option erkennt die Schwachstellen "Use-After-Scope" und "Use-After-Return" aus unserem ersten Beispiel.

Manchmal wird der ganzzahlige Überlauf übersehen. Dies liegt daran, dass Ganzzahlüberläufe nur dann Sicherheitslücken darstellen, wenn sie als Index oder Größe eines Puffers verwendet werden oder wenn der unerwartete Wert des Überlaufs den Fluss des kritischen Sicherheitscodes ändert. Swift 4 fängt die offensichtlichsten Ganzzahlüberläufe beim Kompilieren ab, z. B. wenn die Zahl deutlich größer als der Maximalwert der Ganzzahl ist.

Das Folgende wird beispielsweise nicht kompiliert.

In vielen Fällen kommt die Nummer jedoch dynamisch zur Laufzeit an, z. B. wenn ein Benutzer Informationen in ein UITextField eingibt. Undefiniertes Verhalten Sanitizer ist ein neues Tool in Xcode 9, das einen vorzeichenbehafteten Ganzzahlüberlauf und andere Fehler bei der Nichtübereinstimmung von Typen erkennt. Um es zu aktivieren, gehen Sie zu Produkt > Schema > Schema bearbeiten > Diagnose und aktivieren Sie Undefined Behavior Sanitizer. Setzen Sie dann unter Build Settings > Undefined Behavior Sanitizer Enable Extra Integer Checks auf Yes.

Es gibt noch eine andere erwähnenswerte Sache über undefiniertes Verhalten. Obwohl reine Swift-Zeiger, Referenzen und Kopien von Puffern immer noch hinter den Kulissen verwendet werden, kann es zu Verhaltensweisen kommen, die Sie nicht erwartet haben. Wenn Sie beispielsweise mit der Iteration über Sammlungsindizes beginnen, können die Indizes während der Iteration versehentlich von Ihnen geändert werden.

Hier haben wir nur veranlasst, dass das numbers array auf ein neues Array innerhalb der Schleife zeigt. Worauf weist die number dann hin? Dies wird normalerweise als baumelnde Referenz bezeichnet. In diesem Fall erstellt Swift jedoch implizit eine Referenz auf eine Kopie des Puffers Ihres Arrays für die Dauer der Schleife. Das bedeutet, dass die print-Anweisung tatsächlich 1, 2 und 3 anstelle von 1, 4, 5 ausgibt. Das ist gut! Swift bewahrt Sie vor undefiniertem Verhalten oder einem App-Absturz, obwohl Sie diese Ausgabe möglicherweise auch nicht erwartet haben. Ihre Peer-Entwickler erwarten nicht, dass Ihre Sammlung während der Aufzählung mutiert wird. Seien Sie daher bei der Aufzählung im Allgemeinen besonders vorsichtig, damit Sie die Sammlung nicht ändern.

Daher verfügt Swift 4 zur Kompilierungszeit über eine hervorragende Sicherheitsdurchsetzung, um diese Sicherheitslücken zu schließen. Es gibt viele Situationen, in denen die Sicherheitsanfälligkeit erst zur Laufzeit bei Benutzerinteraktion besteht. Swift enthält auch eine dynamische Überprüfung, mit der viele Probleme auch zur Laufzeit behoben werden können. Die Ausführung über Threads hinweg ist jedoch zu teuer, sodass sie nicht für Multithread-Code ausgeführt wird. Bei der dynamischen Überprüfung werden viele, aber nicht alle Verstöße festgestellt. Daher ist es immer noch wichtig, zuerst sicheren Code zu schreiben!

Wenden wir uns nun einem anderen sehr häufigen Bereich für Sicherheitslücken zu - Code-Injection-Angriffen.

Injection und Format String Attacks

Angriffe auf Formatzeichenfolgen treten auf, wenn eine Eingabezeichenfolge in Ihrer App als Befehl analysiert wird, den Sie nicht beabsichtigt haben. Während reine Swift-Zeichenfolgen nicht für Formatierungszeichenfolgenangriffe anfällig sind, sind dies die CFString-Klassen Objective-C NSString und Core Foundation, die bei Swift erhältlich sind. Beide Klassen verfügen über Methoden wie stringWithFormat.

Angenommen, der Benutzer kann beliebigen Text aus einem UITextField eingeben.

Dies kann eine Sicherheitslücke sein, wenn die Formatzeichenfolge direkt behandelt wird.

Swift 4 versucht, fehlende Formatzeichenfolgenargumente durch Rückgabe von 0 oder NULL zu behandeln. Es ist jedoch besonders besorgniserregend, ob die Zeichenfolge an die Objective-C-Laufzeit zurückgegeben wird.

Während die falsche Vorgehensweise meistens nur zu einem Absturz führt, kann ein Angreifer sorgfältig eine Formatzeichenfolge erstellen, um Daten in bestimmte Speicherorte auf dem Stapel zu schreiben, um das Verhalten Ihrer App zu ändern (z. B. das Ändern einer isAuthenticated-Variablen).

Ein weiterer großer Schuldiger ist NSPredicate, das eine Formatzeichenfolge akzeptieren kann, mit der angegeben wird, welche Daten aus Core Data abgerufen werden. Klauseln wie LIKE und CONTAINS erlauben Platzhalter und sollten vermieden oder zumindest nur für Suchvorgänge verwendet werden. Die Idee ist, die Aufzählung von Konten zu vermeiden, beispielsweise wenn der Angreifer "a*" als Kontonamen eingibt. Wenn Sie die LIKE-Klausel in == ändern, bedeutet dies, dass die Zeichenfolge buchstäblich mit „a*“ übereinstimmen muss.

Andere häufige Angriffe treten auf, indem die Eingabezeichenfolge vorzeitig mit einem einfachen Anführungszeichen beendet wird, sodass zusätzliche Befehle eingegeben werden können. Zum Beispiel könnte ein Login umgangen werden, indem ') OR 1=1 OR (password LIKE '* in das UITextField eingegeben wird. Diese Zeile bedeutet "wo Passwort wie alles ist", wodurch die Authentifizierung insgesamt umgangen wird. Die Lösung besteht darin, Injektionsversuchen vollständig zu entgehen, indem Sie Ihre eigenen doppelten Anführungszeichen in den Code einfügen. Auf diese Weise werden zusätzliche Anführungszeichen des Benutzers als Teil der Eingabezeichenfolge angesehen, anstatt ein spezielles Abschlusszeichen zu sein:

Eine weitere Möglichkeit, sich vor diesen Angriffen zu schützen, besteht darin, einfach nach bestimmten Zeichen zu suchen und diese auszuschließen, von denen Sie wissen, dass sie in der Zeichenfolge schädlich sein können. Beispiele wären Anführungszeichen oder sogar Punkte und Schrägstriche. Beispielsweise ist es möglich, einen Verzeichnisdurchlaufangriff durchzuführen, wenn Eingaben direkt an die FileManager-Klasse übergeben werden. In diesem Beispiel gibt der Benutzer "../" ein, um das übergeordnete Verzeichnis des Pfads anstelle des beabsichtigten Unterverzeichnisses anzuzeigen.

Andere Sonderzeichen können ein NULL-Abschlussbyte enthalten, wenn die Zeichenfolge als C-Zeichenfolge verwendet wird. Zeiger auf C-Strings erfordern ein NULL-Abschlussbyte. Aus diesem Grund ist es möglich, die Zeichenfolge einfach durch Einfügen eines NULL-Bytes zu manipulieren. Der Angreifer möchte die Zeichenfolge möglicherweise vorzeitig beenden, wenn ein Flag wie need_auth=1 vorhanden ist oder wenn der Zugriff standardmäßig aktiviert und explizit deaktiviert ist, z. B. mit is_subscriber=0.

Das Parsen von HTML-, XML- und JSON-Zeichenfolgen erfordert ebenfalls besondere Aufmerksamkeit. Die sicherste Möglichkeit, mit ihnen zu arbeiten, besteht darin, die nativen Bibliotheken von Foundation zu verwenden, die Objekte für jeden Knoten bereitstellen, z. B. die NSXMLParser-Klasse. Swift 4 führt die typsichere Serialisierung in externe Formate wie JSON ein. Wenn Sie jedoch XML oder HTML mit einem benutzerdefinierten System lesen, stellen Sie sicher, dass keine Sonderzeichen aus der Benutzereingabe verwendet werden können, um den Interpreter anzuweisen.

  • < muss &lt werden.
  • > sollte durch &gt ersetzt werden.
  • & sollte &amp werden.
  • Innerhalb von Attributwerten muss jedes " oder ' zu &quot bzw. &apos werden.

Hier ist ein Beispiel für eine schnelle Möglichkeit, bestimmte Zeichen zu entfernen oder zu ersetzen:

Ein letzter Bereich für Injektionsangriffe befindet sich in URL-Handlern. Stellen Sie sicher, dass Benutzereingaben nicht direkt in den benutzerdefinierten URL-Handlern openURL und didReceiveRemoteNotification verwendet werden. Stellen Sie sicher, dass die URL Ihren Erwartungen entspricht und dass ein Benutzer keine willkürlichen Informationen eingeben kann, um Ihre Logik zu manipulieren. Anstatt den Benutzer beispielsweise auswählen zu lassen, zu welchem Bildschirm im Stapel nach Index navigiert werden soll, dürfen nur bestimmte Bildschirme mit einer undurchsichtigen Kennung wie t=es84jg5urw verwendet werden.

Wenn Sie WKWebViews in Ihrer App verwenden, sollten Sie auch die URLs überprüfen, die dort geladen werden. Sie können decidePolicyFor navigationAction überschreiben, mit der Sie auswählen können, ob Sie mit der URL-Anforderung fortfahren möchten.

Einige bekannte Webview-Tricks umfassen das Laden von benutzerdefinierten URL-Schemata, die der Entwickler nicht beabsichtigt hatte, z. B. eine app-id: Starten einer völlig anderen App oder sms: Senden eines Textes. Beachten Sie, dass eingebettete Webansichten keine Leiste mit der URL-Adresse oder dem SSL-Status (dem Schlosssymbol) anzeigen, sodass der Benutzer nicht feststellen kann, ob die Verbindung vertrauenswürdig ist.

Wenn die Webansicht beispielsweise im Vollbildmodus angezeigt wird, kann die URL mit einer Webseite entführt werden, die genau wie Ihr Anmeldebildschirm aussieht, außer dass die Anmeldeinformationen stattdessen an eine schädliche Domain weitergeleitet werden. Andere Angriffe in der Vergangenheit umfassten Cross-Site-Scripting-Angriffe, bei denen Cookies und sogar das gesamte Dateisystem durchgesickert sind.

Die beste Prävention für alle genannten Angriffe besteht darin, sich die Zeit zu nehmen, um Ihre Benutzeroberfläche mithilfe nativer Steuerelemente der Benutzeroberfläche zu gestalten, anstatt einfach eine webbasierte Version in Ihrer App anzuzeigen.

Bisher haben wir uns mit relativ einfachen Arten von Angriffen befasst. Aber lassen Sie uns mit einem fortgeschritteneren Angriff abschließen, der zur Laufzeit stattfinden kann.

Laufzeit-Hacking

So wie Swift bei der Schnittstelle mit C anfälliger wird, bringt die Schnittstelle mit Objective-C separate Schwachstellen in die Tabelle.

Wir haben bereits Probleme mit NSString- und Format-String-Angriffen gesehen. Ein weiterer Punkt ist, dass Objective-C als Sprache viel dynamischer ist und es ermöglicht, lose Typen und Methoden weiterzugeben. Wenn Ihre Swift-Klasse von NSObject erbt, ist sie für Objective-C-Laufzeitangriffe offen.

Die häufigste Sicherheitsanfälligkeit besteht darin, eine wichtige Sicherheitsmethode dynamisch gegen eine andere auszutauschen. Beispielsweise könnte eine Methode, die zurückgibt, wenn ein Benutzer validiert wird, gegen eine andere Methode ausgetauscht werden, die fast immer true zurückgibt, z. B. isRetinaDisplay. Durch die Minimierung der Verwendung von Objective-C wird Ihre App robuster gegen diese Art von Angriff.

In Swift 4 werden Methoden für Klassen, die von einer Objective-C-Klasse erben, nur dann der Objective-C-Laufzeit ausgesetzt, wenn diese Methoden oder die Klassen selbst mit @attribute gekennzeichnet sind. Oft wird stattdessen die Swift-Funktion aufgerufen, selbst wenn das @objc-Attribut verwendet wird. Dies kann passieren, wenn die Methode ein @objc-Attribut hat, aber nie von Objective-C aufgerufen wird.

Mit anderen Worten, Swift 4 führt weniger @objc-Inferenz ein, wodurch die Angriffsfläche im Vergleich zu früheren Versionen begrenzt wird. Um die Laufzeitfunktionen zu unterstützen, müssen Objective-C-basierte Binärdateien jedoch viele Klasseninformationen enthalten, die nicht entfernt werden können. Dies reicht für Reverse Engineers aus, um die Klassenschnittstelle neu zu erstellen und beispielsweise herauszufinden, welche Sicherheitsabschnitte gepatcht werden müssen.

In Swift sind weniger Informationen in der Binärdatei verfügbar, und Funktionsnamen werden entstellt. Das Mangeln kann jedoch durch das Swift-Entwirren des Xcode-Werkzeugs rückgängig gemacht werden. Tatsächlich haben Swift-Funktionen ein konsistentes Namensschema, das angibt, ob jede eine Swift-Funktion ist oder nicht, Teil einer Klasse, Modulname und -länge, Klassenname und -länge, Methodenname und -länge, Attribute, Parameter und Rückgabetyp.

Diese Namen sind in Swift 4 kürzer. Wenn Sie sich Gedanken über Reverse Engineering machen, stellen Sie sicher, dass die Release-Version Ihrer App Symbole entfernt, indem Sie zu Build-Einstellungen > Bereitstellung > Swift-Symbole entfernen gehen und die Option auf Ja setzen.

Sie können nicht nur kritischen Sicherheitscode verschleiern, sondern auch Inline-Code anfordern. Dies bedeutet, dass an jeder Stelle, an der die Funktion in Ihrem Code aufgerufen wird, der Code an dieser Stelle wiederholt wird, anstatt nur an einer Stelle der Binärdatei zu existieren.

Auf diese Weise hat ein Angreifer, der es schafft, eine bestimmte Sicherheitsüberprüfung zu umgehen, keine Auswirkungen auf andere Vorkommnisse dieser Überprüfung, die sich an anderen Stellen Ihres Codes befinden. Jeder Check muss gepatcht oder eingehakt werden, was es viel schwieriger macht, einen Crack erfolgreich durchzuführen. Sie können Code wie folgt einbinden:

Abschluss

Das Nachdenken über Sicherheit sollte ein wichtiger Bestandteil der Entwicklung sein. Die bloße Erwartung, dass die Sprache sicher ist, kann zu Schwachstellen führen, die hätten vermieden werden können. Swift ist für die iOS-Entwicklung beliebt, steht jedoch für MacOS-Desktop-Apps, tvOS, watchOS und Linux zur Verfügung (Sie können es also für serverseitige Komponenten verwenden, bei denen das Potenzial für Exploits bei der Codeausführung viel höher ist). App-Sandboxing kann fehlerhaft sein, z. B. bei Geräten mit Jailbreak, bei denen nicht signierter Code ausgeführt werden kann. Daher ist es wichtig, beim Debuggen immer noch über die Sicherheit nachzudenken und auf Xcode-Hinweise zu achten.

Ein letzter Tipp ist, Compiler-Warnungen als Fehler zu behandeln. Sie können Xcode dazu zwingen, indem Sie zu Build Settings gehen und Warnungen als Fehler behandeln auf Ja setzen. Vergessen Sie nicht, Ihre Projekteinstellungen bei der Migration auf Xcode 9 zu modernisieren, um verbesserte Warnungen zu erhalten, und nutzen Sie nicht zuletzt die neuen Funktionen, die durch die heutige Einführung von Swift 4 verfügbar sind!

Lernen Sie Swift

Wir haben eine vollständige Anleitung erstellt, die Ihnen hilft, Swift zu lernen, unabhängig davon, ob Sie gerade erst mit den Grundlagen beginnen oder fortgeschrittenere Themen untersuchen möchten.

Weitere Informationen zu anderen Aspekten der sicheren Codierung für iOS finden Sie in einigen meiner anderen Beiträge hier auf Envato Tuts+!

Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.