Secure Coding – ein Bericht aus der Praxis
Den Test für eine komplexe Webanwendung hatte sich der Penetration Tester anders vorgestellt: Eine Anwendung mit 4 Bereichen, 10 Nutzerrollen mit verschiedenen Berechtigungen, Erfassung personenbezogener Daten, Email-Versand, Pdf-Generierung, Dateiuploads – irgendwo müssen doch Schwachstellen zu finden sein. Doch an Tag 3 des Tests ließen nennenswerte Befunde immer noch auf sich warten. Aber warum genau?
Die Herausforderung
Jugend trainiert für Olympia und Paralympics ist der größte Schulsportwettbewerb der Welt. Jedes Jahr nehmen rund 10.000 Kinder und Jugendliche in 26 Sportarten – darunter sieben paralympische Disziplinen – teil. Ihr gemeinsames Ziel: Mit ihrer Schule das Bundesfinale in Berlin erreichen und dort um den Bundessieg kämpfen. Die Bundesfinals sind entsprechend Großveranstaltungen bei denen 4.500 Teilnehmende, Betreuungspersonen, Wettkampfleitungen und Helfende zusammenkommen.
Die Veranstaltungen werden organisiert von der Deutschen Schulsportstiftung, die von den 16 Bundesländern und Sportspitzenverbänden getragen wird. Anmeldung, Organisation und Ergebnispublikation der Bundesfinals sollen auf einer zentralen Plattform digitalisiert werden, um Prozesse einfacher zu gestalten. Dafür hatte die Deutsche Schulsportstiftung ein mehrjähriges Softwareprojekt ausgeschrieben.
Im Rahmen dieses Projekts haben wir von QualityMinds in den vergangenen zweieinhalb Jahren mit einem Scrum-Team eine Webapplikation entwickelt. Dank der zentralen Anmeldung der Teilnehmenden und Gäste sind keine händisch gepflegten Excel-Tabellen oder postalisch versandten Teilnahmeausweise mehr nötig. Da die Webapplikation die personenbezogenen Daten sowie wenige Gesundheitsdaten der Teilnehmenden verarbeitet, lag in diesem Projekt ein besonderer Fokus auf der Sicherheit der Anwendung.

Unsere Herangehensweise
Dieser Artikel konzentriert sich auf das Thema Secure Coding doch das Thema Sicherheit betrifft das ganze Team. Sicherheit ist nicht nur ein Thema während des Code-schreibens, sondern im ganzen Lebenszyklus der Software.
Besonders wichtige Fragen waren für uns und den Kunden:
- Wer darf welche Daten zu welchem Zeitpunkt sehen?
- Wer darf die Daten bearbeiten?
- Wer muss an einem Prozess beteiligt sein, und welche Informationen benötigen diese Personen in ihrer jeweiligen Rolle?
Diese Fragen haben uns bereits im Requirements Engineering, in Abstimmung mit dem Kunden und in Refinements beschäftigt. Wenn existierende Prozesse erstmals digitalisiert werden oder ein Email-und-Telefon-Workflow durch eine zentrale Plattform abgelöst wird, ist ein guter Moment, den ganzen Prozess neu zu denken. Dadurch kann der Prozess nutzerfreundlich gestaltet werden und eine wirksame Zugriffskontrolle für die Daten implementiert werden.
Immer, wenn wir neue Aufgabenstellungen für die Entwicklung geplant haben, wurden nötige Sicherheitsmaßnahmen bereits im Refinement diskutiert. Beim ersten Dateiupload stellte sich etwa die Frage, welche Dateiformate akzeptiert werden müssen und wie diese validiert werden können. So haben wir IT-Sicherheit bei der Planung und der Entwicklung neuer Features mitgedacht.
Ressourcen und Tools für Secure Coding
Als ich in Vorbereitung für diesen Artikel mit meinem Kollegen Martin Schmidt über unsere Herangehensweise sprach, sagte er: „Wir haben halt einfach alle Basics beachtet.“ Aber was sind diese Basics?
Secure Coding ist ein weites Feld bei dem es leicht ist, den Überblick zu verlieren. Empfohlen seien an dieser Stelle die OWASP Top 10 Proactive Controls als breiter Überblick, welchen Aspekten man sich bei der Absicherung einer Web-Applikation widmen sollte. Die Top 10 verweisen auf weitere Ressourcen zu jedem Thema sowie auf konkrete Tools, die bei der Implementierung und dem Testen von Maßnahmen helfen können.
Als Basis für unsere Anwendung haben wir etablierte Frameworks verwendet, konkret Spring Boot für das Backend und Angular für das Frontend. Als Identity Management setzen wir Keycloak ein. Sich mit den genutzten Frameworks vertraut zu machen und deren Konfigurationsmöglichkeiten z.B. für Authentication und Authorization zu nutzen ist eine wichtige Grundlage für eine sichere Anwendung. Als weitere „Standardbausteine“ verwenden wir verschiedene Templating-Bibliotheken, um Html-Emails sowie Pdf-Dokumente zu generieren. Durch das Templating können Script-Injection-Angriffe effektiv verhindert werden.
Nachdem wir nun also die absoluten Basics beachten, stellt sich die Frage, wo wir weitermachen sollten? Hier haben uns verschiedene Methoden und Tools weiterführende Antworten gegeben:
In einem internen Threat Modelling Workshop haben wir uns strukturiert Gedanken gemacht, welche Bedrohungen für unsere Anwendung relevant sind und mit welchen Risiken diese einher gehen. Eine unterhaltsame Ergänzung dazu sind Kartenspiele wie Cornucopia. Die Karten geben zahlreiche Anregungen, welche möglichen Bedrohungen berücksichtigt werden sollten. Gleichzeitig macht es der spielerische Ansatz leichter, dass alle im Team sich trauen, ihre Erfahrung beizutragen.
SAST (Static Application Security Testing) – Der Scanner SonarQube hat uns neben Verbesserungspotential bei der Codequalität auch auf mögliche Sicherheitsprobleme hingewiesen.
DAST (Dynamic Application Security Testing) – Ein Scan durch den Zed Attack Proxy kann beispielsweise fehlende Security Headers erkennen.

Speziell auf die Anwendung zugeschnittene Maßnahmen
Einige weiterführende Maßnahmen haben wir speziell auf die Bedarfe unserer Webanwendung zugeschnitten.
Für die Autorisierung verfolgen wir einen Defense-in-Depth-Ansatz. Dies bedeutet, dass für jede Aktion mehrere Autorisierungsschritte in verschiedenen Schichten der Anwendung erfolgen. Für jeden API-Aufruf erfolgt zunächst eine initiale Berechtigungsprüfung basierend auf der Benutzerrolle. Innerhalb des Domänenmodells erfolgt danach eine detaillierte Prüfung. Diese bezieht neben der dauerhaft bestehenden Benutzerrolle z.B. die konkrete Funktion des Benutzers innerhalb einer Veranstaltung, den Status einer Entität oder die Einhaltung von Fristen für bestimmte Aktionen ein.
Wie bereits erwähnt ist ein Dateiupload Teil unserer Anwendung. Im ersten Schritt haben wir dafür eingeschränkt, welche Dateitypen unterstützt werden müssen. Als Basisabsicherung prüfen wir die Dateigröße und den Content-Type aus dem HTTP-Request. Darüber hinaus prüfen wir die Magic Bytes auf Übereinstimmung mit dem Content-Type, um manipulierte Dateien abzulehnen. Die Prüfung kann bequem mit der Bibliothek Apache Tika erfolgen.
Für Dateiuploads und Importe von Dateien haben wir darüber hinaus einen Teil der Verarbeitung ins Frontend verlagert. So findet die Verarbeitung im Browser der Nutzerin statt und die Angriffsfläche des Backends, z.B. auf Dateiparser, wird geringer.
- Bei einem Fotoupload können verschiedene Bild-Dateitypen durch Zeichnen auf einen Canvas in JPEG-Dateien konvertiert werden. Das Backend muss nur JPEG-Dateien akzeptieren.
- Bei einem Dateiupload können verschiedene Bild-Dateitypen und Pdf-Dateien in den Browser geladen werden. Alle werden in Pdf-Dateien konvertiert. Das Backend muss nur PDF-Dateien akzeptieren.
- Bei einem Excel-Dateiupload wird die Datei direkt im Browser mit SheetJS geparst. Dabei wird validiert, dass die Daten grundlegend das erwartete Format haben. Die Datei wird im Frontend verarbeitet und die einzelnen Datensätze auf Data Transfer Objects gemappt. Das Backend muss nur eine Liste von Data Transfer Objects akzeptieren.
Im Konfigurationsbereich innerhalb der Anwendung, der für einen eingeschränkten Nutzerkreis zugänglich ist, können Textbausteine hinterlegt werden. Auf anderen Seiten zeigen wir diese Textbausteine mit entsprechender Formatierung an. Um die Textformatierung zu unterstützen, haben wir uns für ein HTML-Format der Textbausteine entschieden. Das eröffnet die Möglichkeit von Script-Injection-Angriffen, was wir natürlich verhindern wollen. Mit dem OWASP Java HTML Sanitizer schränken wir die erlaubten HTML-Elemente und Kombinationen auf eine sichere Auswahl ein. Die Logik für die Sanitisierung ist Teil eines Value Objects HtmlText im Sinne des Domain Driven Design. Dadurch sind HTML-Textbausteine im Code direkt als solche erkennbar und es ist sichergestellt, dass die Sanitisierung für alle HTML-Textbausteine erfolgt.
Tests für die IT-Sicherheit
Mit der Umsetzung der Maßnahmen sind wir fertig? Nicht ganz: Wie auch andere Teile der Software sollten die Sicherheitsmaßnahmen getestet werden.
Wie wichtig solche Tests sind, zeigt ein Beispiel aus dem Projekt: Wir setzen eine Cloud-Speicher-Lösung für hochgeladene Dateien ein. Dort haben wir das Malware-Scanning aktiviert, aber zunächst nicht getestet. Erst bei einem Test stellte sich heraus, dass die Konfiguration des Malware-Scanners nicht ausreichend war: Die Dateien wurden zwar gescannt, aber die Scan-Ergebnisse sind nur mit bestimmten Berechtigungen sichtbar. Für das Team war also zunächst nicht erkennbar, ob der Scan stattgefunden hat und welche Dateien als auffällig markiert wurden. Desweiteren haben wir die automatische Quarantäne für auffällige Dateien erst nachträglich eingeschaltet.
Ergänzend zu den Tests des Entwicklungsteams haben wir einen externen Penetration Test durchführen lassen, um unsere Anwendung auf Herz und Nieren zu prüfen. Dabei haben wir unseren Penetration Tester überrascht, denn er musste ausgiebig suchen, um Verbesserungspotentiale aufzudecken. Der Test hat somit den hohen Sicherheitsstandard unserer Web-Applikation bestätigt.
Sicherheit als Teamsport
Eins hat uns der überraschte Penetration Tester noch mitgegeben: Was auch immer ihr gemacht habt, um diese Anwendung so sicher zu bekommen: Macht es weiter so – und am Besten schreibt es auf. Das Ergebnis ist dieser Text, der unsere technischen Maßnahmen erläutert. Die Quintessenz ist jedoch: “Sicherheit ist ein Teamsport”.
Wir haben Sicherheit von Anfang an mitgedacht. Wir nutzen die Expertise des gesamten Teams, um die Anwendung Schritt für Schritt sicherer zu machen. Verschiedene Anlässe von Refinement bis Threat Modelling Workshop geben die Möglichkeit, alle Perspektiven einzubringen, Risiken zu erkennen und gezielte Maßnahmen zu planen.
Schreib uns eine Mail – wir freuen uns auf deine Nachricht! hello@qualityminds.de oder auf LinkedIn