Sichere Softwareentwicklung – Teil 1 Grundsätze für sichere Softwareentwicklung
Viele Onlinedienste und Websites sind anfällig für Angriffe. Die Entwicklung moderner Software für Webanwendungen ist heutzutage so komplex, dass Fehler trotz intensiver Prüfung nicht oder nur schwer erkennbar sind. Das demonstrierte auch die Heartbleed-Schwachstelle in der Open-Source-Bibliothek OpenSSL eindrucksvoll. Wir zeigen die gängigen Herausforderungen, mit denen Entwickler konfrontiert sind und wie man sie bewältigt.
Anbieter zum Thema

Zu den am meisten verbreiteten Sicherheitsschwachstellen in Webanwendungen gehören Injektions-, XSS- und CSRF-Verwundbarkeiten. Sie gelten als das am meisten genutzte Einfallstor für Cyberkriminelle. Schaffen Hacker aufgrund dieser Schwachstellen im System den Zugriff auf sensible Daten der Kunden, lassen sich diese manipulieren und schädigen im schlimmsten Fall dauerhaft die gesamte IT-Infrastruktur. Doch wo liegt die Quelle der Verletzlichkeit und wie lässt sie sich reduzieren?
1. Grundsatz der sicheren Softwareentwicklung : Injektionen sowie Schwachstellen verhindern
Injektionsschwachstellen entstehen, wenn jemand Benutzereingaben zur Erstellung von Anweisungen oder Abfragen (z. B. SQL-Abfrage) verwendet und ohne ausreichende Überprüfung an einen Interpreter weitersendet. Durch Manipulation der Eingabesyntax führt ein Angreifer unerwünschte Befehle aus und erhält unbefugten Zugriff auf empfindliche Daten (z. B. ermöglicht eine SQL-Injektion in einer Webanwendung einen Datenbankzugriff im Backend).
XSS-Schwachstellen (Cross-Site Scripting) entstehen, wenn Webanwendungen Benutzereingaben akzeptieren und Ausgaben ohne Validierung generieren (z. B. Eingabe eines Suchbegriffs durch den Benutzer und anschließende Anzeige der Benutzereingaben auf der Seite mit den Suchergebnissen). Über solche Schwachstellen installieren Angreifer einen Schadcode in einer Webanwendung – häufig über bestimmte gut vorbereitete URLs. Dieser führt sich automatisch mit aus, wenn die Anwendung im Web-Browser des Kunden startet.
Bei einem CSRF-Angriff (Cross-Site Request Forgery) führt ein Angreifer HTTP-Anfragen über den Web-Browser eines Kunden aus. Aus Sicht der Anwendungen sehen die Anfragen legitim aus und werden im Kontext und mit den Rechten des angemeldeten Benutzers bearbeitet. Die Anwendung unterscheidet nicht zwischen den Anfragen des rechtmäßigen Nutzers und den Anfragen des Angreifers. Derartige Schwachstellen stellen immer eine Bedrohung für Kunden und deren Daten dar.
Tipps zur Programmierung: Zu den nützlichen Anwendungen zählen Benutzereingaben, die nur im Bedarfsfall zum Einsatz kommen. Weiteren Schutz bieten Eingaben, die gefiltert und geprüft wurden, bevor der Entwickler sie erstmalig verarbeitet. Dieser First-Line-of-Defense-Ansatz schützt Anwendungen vor Injektionsangriffen.
Alle modernen Programmiersprachen und Frameworks bieten in der Regel getestete Routinen zur Filterung von Benutzereingaben. Sie senken deutlich das Risiko für einen Angriff. Bei eigenen Methoden besteht immer die Gefahr, etwas zu übersehen.
Die Implementierung von Funktionen zum Anlegen, Lesen, Ändern oder Löschen von Daten (sogenannte CRUD-Methoden, die Abkürzung steht für Create, Datensatz anlegen, Read oder Retrieve, Datensatz lesen, Update, Datensatz aktualisieren und Delete oder Destroy, Datensatz löschen) erfolgt am besten mit den integrierten Funktionalitäten des jeweils verwendeten Frameworks. Der Fachbegriff hierzu lautet „Scaffolding“ und viele Frameworks bieten geeignete Methoden, um auf Knopfdruck die nötigen Eingabemasken und die Programmlogik auf Basis eines Datenmodells zu erzeugen.
Nachhaltige Systemschäden lassen sich verhindern, wenn die Interaktion von Webanwendungen auf Datenbanken basiert, die nur definierte Befehle zulassen, die für die Funktionalität der Anwendung notwendig sind. Die Beschränkung auf bestimmte Befehle verhindert nachhaltige Systemschäden, wenn es einem Angreifer gelingt, Schadcode zu injizieren.
2. Grundsatz der sicheren Softwareentwicklung : Trennung von Datenverarbeitung und Datendarstellung
Als wesentlich bei der Verarbeitung von Daten (Anlegen, Lesen, Ändern oder Löschen) erweist sich die Trennung von Darstellungslogik (z. B. Ausgabe im Web-Browser) und internen Anwendungslogik. Hierzu etablierte sich in den letzten Jahren das sogenannte Model-View-Controller (MVC) Pattern.
Anwendungen, die dem MVC-Pattern folgen, bestehen aus einem oder mehreren Datenmodellen (Model), Darstellungsschichten (Views) und Programmsteuerungen (Controller). Durch diese Trennung reduziert das MVC-Pattern den Aufwand für Anpassungen an einzelne Komponenten der Anwendung und erhöht die Wiederverwendbarkeit dieser Elemente.
Das Datenmodell (Model) beschreibt die von der Anwendung verarbeiteten Daten, ihren Datentyp, ihren Wertebereich usw. und ist unabhängig von der Darstellung und Steuerung innerhalb der Anwendung. Die Darstellungsschicht (View) zeigt die Darstellung der Daten gemäß dem Datenmodell und nimmt Benutzerinteraktionen entgegen. Die Programmsteuerung (Controller) verwaltet eine oder mehrere Darstellungen (Views), nimmt Benutzerinteraktionen von ihnen entgegen, wertet sie aus und handelt entsprechend.
Durch die Trennung von Anwendungslogik und Datendarstellung vermeidet der Entwickler, dass sich wichtige und sicherheitsrelevante Funktionen versehentlich in die Darstellungsschicht auslagern und der Angreifer einfacher das Sicherheitssystem umgeht. Die Trennung erleichtert auch die Entwicklung von einem oder mehreren Frontends unabhängig von der Anwendungslogik oder dem Datenmodell. Insbesondere bei Anwendungen mit Responsive Design werden verschiedene Frontends nicht mit dem eigentlichen Anwendungscode vermischt. Der Programmcode bleibt klar strukturiert, was auch die spätere Wartung und Weiterentwicklung der Anwendungen erleichtert. Darüber hinaus erhöht sich die Wiederverwendbarkeit einzelner Code-Komponenten durch die strikte Trennung der Programmcodes. So greifen verschiedene Anwendungen auf ein Datenmodell zu oder ein Datenmodell lässt sich durch verschiedene Ansichten darstellen (z. B. eine Übersichtsansicht, eine Detailansicht, eine Ansicht zur Bearbeitung der Daten usw.).
Tipps zur Programmierung: Hilfreich bei der Programmierung erweisen sich Entwickler-Frameworks, die das MVC-Pattern unterstützen und Werkzeuge für die Erstellung von Controllers, Views und Models bereitstellen. Das Datenmodell beschreibt beispielsweise Datentyp und Wertebereiche, der Controller implementiert Routinen zur Steuerung der Anwendungslogik, der View-Bereich stellt die Daten dar.
Scaffolding zur Implementierung von MVC-Programmcode
Entwickler-Frameworks unterstützen häufig die Erstellung von Programmcode für Models, Views und Controller durch sogenanntes „Scaffolding“. Die Vorlagen der Frameworks erzeugen standardisierte CRUD-Operationen. Das spart Zeit und reduziert den Stress während der Entwicklung. Und nicht nur das – diese Vorlagen sind oft sehr robust, und der generierte Quellcode kapselt Variablen und Eingabeparameter mit Sicherheitsmechanismen, die das Framework bereitstellt, ab. Bei der Entwicklung neuer Anwendungen bieten sich fertige Entwicklungsframeworks (Liste hinterlegen) an, die das MVC-Pattern unterstützen und Scaffolding-Mechanismen anbieten.
3. Grundsatz der sicheren Softwareentwicklung: Daten vor der Verarbeitung immer validieren
Die konsequente Validierung, also die Verifizierung von Eingabe- und Ausgabedaten, stellt ein Grundprinzip für die Entwicklung von korrekt funktionierenden, stabilen und sicheren Anwendungen dar. Fehlerhafte Datenpools oder gar Sicherheitsschwachstellen entstehen oftmals aufgrund fehlerhafter Prüfung von Syntax und Semantik (siehe Grundsatz 1). Die fehlende Datenvalidierung und -filterung zählt dabei zu den häufigsten Hacker begünstigenden Umständen und ermöglicht umfangreiche Angriffe auf Webanwendungen (z. B. SQL-Injektionen für den Zugriff auf Datenbanken). Die Vertraulichkeit, Integrität und Verfügbarkeit der Daten unserer Nutzer ist daher unmittelbar gefährdet. Häufig erhalten Angreifer über solche Schwachstellen nicht nur Zugriff auf Daten, sondern auch auf die Server, auf denen diese Anwendungen laufen.
Gefahr von Verlust der Datenintegrität und niedriger Datenqualität
Die Integrität der Daten erweist sich neben der Vertraulichkeit und Verfügbarkeit als ein wichtiges Merkmal. Ohne ausreichende Validierung besteht die Gefahr der Unvollständigkeit oder sie erweisen sich als einfach falsch (z. B. negatives Alter einer Person). In diesem Fall spricht man auch von einer geringen Datenqualität oder einer Abweichung vom Datenmodell. Die Auswirkungen solcher fehlerhaften Datensätze breiten sich je Anwendungslogik weiter aus und verursachen Fehler in der Weiterverarbeitung innerhalb der Anwendung.
Tipps zur Programmierung: Hauptsächlich geht es bei einer Softwareentwicklung um die Verteidigung in der Tiefe (defense in depth). Es ist eine Methode, die Sicherheit durch mehrere Schutzmaßnahmen kennzeichnet. Sicher gewählte Anwendungen überprüfen die Korrektheit der verarbeiteten Daten an verschiedenen Stellen während der Verarbeitung. Das heißt – umgeht der Angreifer einzelne Prüfroutinen, schlagen die übrigen Warnsysteme Alarm und die Anwender-Tools reagieren entsprechend. Im Datenmodell (Modell) definieren sich die richtigen Datentypen und Wertebereiche. Die Anwendungslogik (im Controller) verarbeitet die Daten und überprüft, ob diese semantisch gültig sind.
Prüfung und Validierung von Daten
Der Softwareingenieur überprüft bei der Entwicklung von Funktionen zur Datenverarbeitung, beispielsweise zur Speicherung von Benutzereingaben in einer Datenbank oder zur Durchführung mathematischer Operationen, ob sich Werte als zuverlässig darstellen. Dies ist insbesondere bei Benutzereingaben und Übergabeparametern in Funktionen erforderlich. Einerseits sichert sich das Unternehmen dadurch die Datenqualität, andererseits verhindert es so Manipulationen oder gar Angriffe auf die Anwendung und Daten der Nutzer.
4. Grundsatz der sicheren Softwareentwicklung: Daten zwischen Web-Browser und Anwendung vor externer Einsicht schützen
Daten, die im Austausch zwischen Servern und Web-Browsern stehen, benötigen Schutz vor externer Einsicht. Eine sichere Datenübertragung zwischen Client und Server (z. B. über eine HTTP(S)-gesicherte Verbindung) ist wichtig, da die Bevölkerung zunehmend freie WLAN-Hotspots mit unverschlüsselten Verbindungen akzeptiert. Angreifer nutzen diese Lücke, um private und sensible Informationen wie Passwörter, Nutzersitzungen oder auch persönliche Daten einzusehen.
Einsicht von Fremden in übertragene Daten vermeiden
Erhält der Angreifer Einsicht in die Datenübertragung zwischen unseren Servern und den Nutzern, bekommt er möglicherweise Einblick in sensible und schutzwürdige Informationen. Die Vertraulichkeit der Daten ist damit nicht mehr gegeben, vor allem wenn Informationen wie Benutzernamen und Passwörter von Fremden einsehbar sind. So erhalten Unbefugte Zugang zu den Anwendungen und greifen unter vorgegebener Identität und mit den Rechten der betroffenen Nutzer auf die Daten zu und manipulieren diese. Ursachen hierfür liegen in der fehlerhaften Implementierung von Schutzmechanismen oder in der Verwendung veralteter und unsicherer Verfahren zur Verschlüsselung.
Verschlüsselung der Übertragung (HTTP(S), TLS)
Sichere Anwendungen verschlüsseln sensible Daten (z. B. mit TLS 1.2, TLS 1.3), sodass ein Angreifer keinen Zugang zu den Daten bekommt – auch dann nicht, wenn er sich bereits in die Kommunikation zwischen Web-Browser und Anwendung eingeklinkt hat (zum Beispiel durch einen Man-in-the-Middle-Angriff). Über das HTTP(S)-Protokoll verschlüsselte Internetverbindungen liefern dabei einen hohen Sicherheitsstandard. Dasselbe gilt für die Datenübertragung über das Internet. Auch hier bieten sich verschlüsselte Protokolle an. In diesem Zusammenhang stellt der SFTP einen enormen Vorteil gegenüber dem unverschlüsselten FTP dar, so wie SSH anstelle von Telnet.
Die Sicherheitsschwachstellen POODLE, Heartbleed und BEAST zeigen deutlich, dass die verwendete Übertragungsverschlüsselung immer auf dem neuesten Stand der Technik sein muss, um die Vertraulichkeit sensibler Daten zu gewährleisten und dauerhafte Schäden an den Systemen der Nutzer zu vermeiden.
Die Verschlüsselung nicht selbst entwickeln – Standardlösungen verwenden
Grundsätzlich bieten alle modernen Programmiersprachen und Frameworks Möglichkeiten zur Implementierung von bereits erprobten Verschlüsselungsverfahren für die Übertragungsverschlüsselung (z. B. TLS mit Perfect Forward Secrecy (PFS)), die bereits mit aufwendiger Standardisierungsprozesse eingeführt wurden. Bei eigens entwickelten Verschlüsselungsverfahren besteht immer die Gefahr, etwas zu übersehen. Ein einprägsames Zitat von Brian Hatch zu diesem Thema lautet: „Jeder Programmierer versucht irgendwann, einen eigenen Verschlüsselungsalgorithmus zu entwickeln. Kurz gesagt: Lassen Sie das!“
5. Grundsatz der sicheren Softwareentwicklung: Die Nutzer der Anwendung im Auge behalten
Fehler in der Nutzer- und Sitzungsverwaltung von Webanwendungen führen oftmals zu Sicherheitsschwachstellen. Beispielsweise durch Authentifizierungsfehler, unzureichende Prüfroutinen während des Zurücksetzens des Passworts oder durch unvollständige Prüfungen der jeweiligen Berechtigungen bei der Ausführung von Aktionen innerhalb der Anwendung (Datenzugriff, Änderungen, Datensätze löschen). Daher ist es wichtig, den Nutzer und seine Berechtigungen innerhalb einer Sitzung in den Anwendungen jederzeit im Auge zu behalten. Dies gilt insbesondere für die Prüfung von Berechtigungen bei der Ausführung von CRUD-Operationen (Erstellen, Lesen, Aktualisieren und Löschen).
Es ist wichtig, Nutzersitzungen ausreichend zu sichern, um Fremden den Zugriff auf die Anwendungen oder Cookies mit Sitzungsinformationen (z. B. SessionID) zu verwehren. Ebenso führen Fehler bei der Implementierung von Funktionen zum Passwort zurücksetzen („Passwort vergessen“) häufig dazu, dass Fremde Einblick in Nutzerkonten erhalten. Sichere Anwendungen und Verfahren stellen daher einen wichtigen Schutz vor Bedrohungen dar.
Wichtig ist die vollständige und robuste Implementierung von Berechtigungsprüfungen, um Angreifern keine Chance auf Manipulierung oder Löschung der Daten zu geben. Der unbefugte Zugriff auf Daten oder Funktionen innerhalb unserer Anwendungen gefährdet unmittelbar die Vertraulichkeit, Integrität und Verfügbarkeit der Daten unserer Nutzer und stellt eine Bedrohung für IT-Infrastrukturen dar.
Tipps zur Programmierung: Für die sichere Implementierung von Nutzer-An- und -Abmeldefunktionen empfehlen sich Standardverfahren, die Entwicklungsframeworks. Je nach Bedarf bieten sich auch zusätzliche Sicherheitsprüfungen durch einen zweiten Entwickler an.
Bei der Implementierung von CRUD-Operationen (Funktionen zum Erstellen, Lesen, Ändern und Löschen von Daten) in den Anwendungen stellen die obligatorischen Berechtigungsprüfungen eine weitere Regel dar. Zu Beginn einer jeden CRUD-Operation ist zu prüfen, ob der aktuell angemeldete Benutzer berechtigt ist, den jeweiligen Vorgang für den betroffenen Datensatz durchzuführen. Die mithilfe von Scaffolding erstellten Frameworks, die bei CRUD-Verfahren zum Einsatz kommen, enthalten in der Regel diese Berechtigungsprüfungen und dienen während der Entwicklung als Ressourcen.
Wer diese Grundsätze berücksichtigt, ist auf dem richtigen Weg, aber es gibt noch mehr, das kommt im zweiten Teil.
:quality(80)/images.vogel.de/vogelonline/bdb/1604400/1604450/original.jpg)
Sichere Softwareentwicklung – Teil 2
Pflegeanleitung für sichere Software
Über den Autor: Pierre Gronau ist seit über 25 Jahren für namhafte Unternehmen als Senior IT-Berater mit umfangreicher Projekterfahrung tätig. Zu seinen Kompetenzfeldern gehören Server-Virtualisierungen, IT-Sicherheit, moderne Cloud- und Automationslösungen sowie Informationsschutz in kritischen Infrastrukturen.
(ID:46085943)