Blog
Wie Sie Ihre Webanwendung mit statischen Anwendungstests sicherer machen (TEIL 1 von 5 in der Serie Application Security Testing)

In dieser Blogserie werden wir uns mit verschiedenen Arten von Application Security Testing (AST), Software Composition Analysis (SCA) und Secret Scanning. Sie werden verwendet, um Sicherheitsschwachstellen in Anwendungen zu identifizieren. Sie können sie zum manuellen Testen von Anwendungen und/oder zur Automatisierung verwenden, indem Sie sie in eine CI/CD-Pipeline einbinden. Ich beginne mit einer kurzen Erklärung, wie sie funktionieren und was ihre Vor- und Nachteile sind. Nach der Erklärung werden wir uns die Hände schmutzig machen und einige Tools manuell ausprobieren. Im letzten Blog dieser Serie werde ich Ihnen zeigen, wie Sie die Tools in einer CI/CD-Pipeline einsetzen können.
Eine kleine Warnung, bevor wir weitermachen. Wenn Sie erwarten, dass der Einsatz dieser Tools alle Ihre Sicherheitsprobleme lösen wird, werden Sie enttäuscht sein. Um diese Tools effektiv zu nutzen, ist es sehr wichtig, eine Kultur zu schaffen, in der sich jeder für die Sicherheit verantwortlich fühlt. Das bedeutet auch, dass DevOps-Teams und Sicherheitsteams zusammenarbeiten müssen, um die besten Ergebnisse zu erzielen.
Um zu demonstrieren, wie die Tools zum Testen der Anwendungssicherheit funktionieren, habe ich eine kleine und einfache verwundbare Java Spring Boot-Anwendung erstellt. Den Quellcode für diese Anwendung finden Sie hier: verwundbare Anwendung .
In diesem ersten Blog werden wir uns mit einer Art von Anwendungssicherheitstests befassen, die als Static Application Security Testing (SAST) bezeichnet wird. In den kommenden Blog-Beiträgen werden wir uns mit dynamischen Anwendungstests (DAST), interaktiven Anwendungstests (IAST), Software Composition Analysis (SCA), geheimen Scans und der Verwendung dieser Testtools in einer CI/CD-Pipeline beschäftigen.
[caption id="attachment_58560" align="alignnone" width="1024"]
Abbildung 1: SAST und andere Formen von AST während der CI/CD-Phasen[/caption]
Zunächst ein wenig Theorie über statische Sicherheitstests für Anwendungen. Von nun an werde ich mich auf Static Application Security Testing als SAST beziehen. SAST-Tools können nach Sicherheitsschwachstellen suchen, ohne den Code auszuführen. Je nach Tool kann es entweder den Quellcode, den Bytecode oder die Binärdateien analysieren. Das SAST-Scanning kann während der Code-Phase erfolgen, zum Beispiel über Ihre lokale Befehlszeilenschnittstelle (CLI) und/oder Ihre integrierte Entwicklungsumgebung (IDE). Und in der Continuous Integration (CI) Umgebung während der Build-Phase.
Auf einer hohen Ebene funktioniert SAST wie der in Abbildung 2 dargestellte Prozess. Modelle werden aus dem Quellcode, dem Bytecode oder den Binärdateien extrahiert. Bei diesen Modellen kann es sich um Zwischendarstellungen wie eine Symboltabelle, einen abstrakten Syntaxbaum, ein Kontrollflussdiagramm oder ein Aufrufdiagramm handeln. Anschließend werden sie durch verschiedene Arten von Analysemethoden wie Datenflussanalyse, Mustervergleich und Kontrollflussanalyse analysiert. Während der Analysephase werden Regeln angewandt, um festzustellen, ob eine Sicherheitslücke vorhanden ist. Das Ergebnis der Analysephase ist ein Bericht mit den gefundenen Sicherheitsschwachstellen.
[caption id="attachment_58561" align="alignnone" width="1016"]
Abbildung 2: Übersicht über die Funktionsweise von SAST[/caption]
Was alle SAST-Tools gemeinsam haben, ist, dass sie Regeln verwenden, um Schwachstellen zu finden. Diese Regeln sind sprachspezifisch. Daher ist es wichtig, dass das von Ihnen gewählte Tool eine gute Unterstützung für die verwendeten Programmiersprachen bietet. SAST hat einige Vor- und Nachteile:
Vorteile
- Schnell
- Finden Sie Schwachstellen frühzeitig im Lebenszyklus der Softwareentwicklung (sogar in der IDE)
- Hohe Code-Abdeckung
- Gibt den Ort des entdeckten verwundbaren Codes an
- Kann Syntaxverletzungen, gefährliche Muster, Programmierfehler und Verstöße gegen den Code-Standard finden
Benachteiligungen
- Hohe Wahrscheinlichkeit einer großen Anzahl von Fehlalarmen
- Qualitativ hochwertige Regeln für bestimmte Sprachen erforderlich, um falsche Negative zu vermeiden
- Schlecht bei der Suche nach logischen Schwachstellen, da der Kontext fehlt
- Kann keine Laufzeit-Schwachstellen finden
Um die besten Ergebnisse zu erzielen, ist es sehr wichtig, das SAST-Tool Ihrer Wahl fein abzustimmen. Andernfalls ist die Wahrscheinlichkeit groß, dass Sie mit Ergebnissen überschwemmt werden. Beginnen Sie nicht mit Dutzenden von verschiedenen Regeln für eine große Codebasis, sondern mit einigen wenigen Regeln, die das höchste Risiko in Ihrem Kontext abdecken. Die Sicherheitsabteilung wird Ihnen dabei helfen können!
Nun, da das aus dem Weg geräumt ist, lassen Sie uns praktisch werden und ein Open-Source-SAST-Tool namens Semgrep verwenden, um unsere anfällige Java-Anwendung zu scannen. Semgrep analysiert den Quellcode und unterstützt eine breite Palette von Programmiersprachen. Wenn Sie wissen möchten, wie es funktioniert, schauen Sie sich das an: Semgrep Engine Übersicht.
Ein großer Vorteil von Semgrep ist, dass es sehr einfach ist, Ihre eigenen Regeln zu erstellen. Semgrep hat auch eine große Community, die bei der Erstellung von Regeln hilft. Der Einfachheit halber werde ich die CLI-Version von Semgrep verwenden. Sie können Semgrep hier kostenlos herunterladen: Semgrep.
Wie bereits erwähnt, arbeiten SAST-Tools mit sprachspezifischen Regeln. Das Gleiche gilt für Semgrep. Da es sich hier um eine Demonstration mit einer kleinen Anwendung handelt, werde ich meinen eigenen Rat ignorieren und alle Regeln verwenden, die Semgrep für relevant hält, indem ich den automatischen Konfigurationsmodus verwende. Semgrep wird den Code analysieren und die verwendeten Programmiersprachen identifizieren. Sobald Semgrep mit der Identifizierung fertig ist, lädt es die entsprechenden Regeln aus dem Semgrep-Register herunter und scannt die Anwendung. Das Register enthält alle offiziellen Semgrep-Regeln. Sie können es hier finden: Semgrep-Register. Um Semgrep im Autokonfigurationsmodus auszuführen, verwenden Sie den folgenden Befehl im Quellcode unserer verwundbaren Anwendung in der Befehlszeilenschnittstelle:
semgrep --config auto <Pfad zum Quellcode unserer verwundbaren Anwendung>
Wenn Sie bestimmte Regeln ausführen möchten, ersetzen Sie den Teil "auto" durch den Remote-Regelsatz oder eine lokale Regel (yaml-Datei). Weitere Informationen hierzu finden Sie unter Semgrep-Regeln ausführen.
Die Ergebnisse des automatischen Konfigurations-Scans unserer anfälligen Anwendung sind in Abbildung 3 dargestellt .
[caption id="attachment_58562" align="alignnone" width="802"]
Abbildung 3: Semgrep-Ergebnisse mit automatischer Konfiguration[/caption]
Semgrep hat 3 Sicherheitslücken gefunden. Alle Probleme befinden sich in der Datei PostController.java. Es scheint ein Problem mit der Art und Weise zu geben, wie SQL in diesem Controller gehandhabt wird. Wenn wir die Zeilennummern 24, 27 und 45 auflösen, stellen wir fest, dass Semgrep sich über die folgenden zwei Operationen im PostController beschwert: /posts und /post/{id}. Schauen wir uns die Ergebnisse an und sehen wir uns den Code an.
Der Code der Operation /posts wird hier angezeigt:
[caption id="attachment_58563" align="alignnone" width="870"]
Abbildung 4: /posts GET Operation in PostController.java[/caption]
Semgrep sagt uns, dass es einen formatierten 'String' in einer SQL-Anweisung entdeckt hat und dass dies zu einer SQL-Injection führen könnte. Was in diesem Fall sicherlich zutrifft. Diese Sicherheitslücke ermöglicht es einem Angreifer, die von dieser Anwendung verwendete Datenbank zu kompromittieren.
Das Problem ergibt sich aus der Art und Weise, wie die SQL-Abfrage erstellt und ausgeführt wird. In Zeile 24 wird eine SQL-Abfrage erstellt, indem nicht überprüfte Benutzereingaben vom Typ 'String' (die ID) in einen 'String' namens query verkettet werden. Dadurch erhält der Benutzer die Kontrolle über das Format des 'String' und damit der SQL-Abfrage. Diese 'String' genannte Abfrage wird dann von statement.executeQuery in Zeile 27 ausgeführt. Wie in der Dokumentation beschrieben, ist Statement nur für einfache SQL-Abfragen ohne Parameter gedacht.
Dies ist ein klassisches Beispiel für eine SQL-Injektion. Sie können dies überprüfen, indem Sie die Anwendung ausführen und die SQL-Injection am Endpunkt /posts?postId ausnutzen. Navigieren Sie in Ihrer Befehlszeilenschnittstelle zum Quellcode und führen Sie den folgenden Befehl aus: java -jar vulnapp-0.0.1-SNAPSHOT.jar
Gehen Sie nun zu"http://localhost:8080/posts?postId=1' union select password from users --". Das Passwort des ersten Benutzers in der Benutzertabelle wird auf der Seite neben den Ergebnissen aller Beiträge mit der ID 1 angezeigt (siehe Abbildung 4).
[caption id="attachment_58565" align="alignnone" width="722"]
Abbildung 5: SQL Injection über den Abfrageparameter postId in PostController.java[/caption]
Dank Semgrep sind wir auf eine SQL-Injection-Schwachstelle in unserem Code aufmerksam geworden. Semgrep gibt sogar an, wie wir dieses Problem beheben können. Wir sollten Prepared Statements anstelle von Statements verwenden. Ich werde nicht näher darauf eingehen, wie das funktioniert, aber Sie können sich die Implementierung einer vorbereiteten Anweisung in der addPost-Methode in Zeile 58-67 in PostController.java ansehen und für die Dokumentation hier klicken. Als Bonus reduziert eine vorbereitete Anweisung auch die Ausführungszeit und verbessert somit die Leistung unserer Anwendung! Dies deckt zwei der drei Befunde ab, den Befund in aus Zeile 24 und 27.
Der letzte Befund, den Semgrep fand, war die gleiche Art von Problem wie in Zeile 24. Es befindet sich bei der Operation /post/{id} in Zeile 45 und der Code ist in Abbildung 6 dargestellt. Wieder einmal verketten wir Benutzereingaben zu einem 'String' namens query und führen diesen unsicher aus, richtig?
[caption id="attachment_58564" align="alignnone" width="751"]
Abbildung 6: /posts/{id} Operation in PostController.java[/caption]
Falsch, diese Abfrage wird überhaupt nicht ausgeführt. Wie man so schön sagt: "Der Teufel steckt im Detail". In Zeile 44 fragen wir ausdrücklich nach einer ID vom Typ 'Long'. Ein Payload wie"http://localhost:8080/post/1' union select h2version() --" wird von der Anwendung abgelehnt, weil "1' union select h2version() --" wird nicht zum Typ 'Long' aufgelöst. Da wir keine Zeichenketten einfügen können, sondern nur Zahlen. Es ist nicht möglich, diesen Code auszunutzen. Eine kleine Randbemerkung: Wenn es möglich wäre, diesen Code auszunutzen, müssten wir die Nutzlast "1' union select h2version() -" URL-kodieren und über einen Web-Proxy wie Burp senden. Da der Browser die URL automatisch dekodiert, würde dies zu einer fehlerhaften URL führen.
Nun stellt sich also die Frage, ob es sich um ein falsches Positiv handelt. Ich denke, das hängt von Ihrer Definition von "falsch positiv" ab. Die Verkettung von Benutzereingaben in einer SQL-Abfrage ist ganz sicher ein Rezept für eine Katastrophe und sollte vermieden werden. Wenn jemand den Typ 'Long' in 'String' ändert, ist die Anwendung anfällig für SQL-Injection. Auch wenn es derzeit keine Sicherheitslücke gibt, die ausgenutzt werden kann, würde ich dennoch empfehlen, eine vorbereitete Anweisung zu verwenden und zumindest einen Kommentar über die Bedeutung des Typs 'Long' hinzuzufügen. Meiner Meinung nach handelt es sich also nicht um einen Fehlalarm. Allerdings würde ich der Behebung dieser Schwachstelle eine geringere Priorität einräumen als der anderen SQL-Injection.
Wie ich bereits erwähnt habe, können Sie Semgrep auch in Ihrer CI-Pipeline verwenden. Im letzten Blog dieser Serie werde ich Ihnen zeigen, wie. Wenn Sie es nicht abwarten können, sehen Sie sich die Dokumentation unter Semgrep in CI an.
Damit ist der Blog über SAST abgeschlossen. Verpassen Sie nicht die nächste Ausgabe, in der wir mit Dynamic Application Security Testing (DAST) prüfen werden, ob wir in der anfälligen App Schwachstellen übersehen haben.
Verfasst von
Maarten Plat
Unsere Ideen
Weitere Blogs
Contact



