Skip to main content

Umgang mit Sicherheitslücken in Spring Boot

Artikel von
feature open source

29. November 2023

0 Min. Lesezeit

In der Softwareentwicklung gehört die Verwaltung von Abhängigkeiten zu den zentralen Aufgaben, wenn Sie robuste und sichere Anwendungen erstellen möchten. Spring Boot ist bei Java-Entwicklerinnen und -Entwicklern beliebt und erleichtert die Entwicklung von Anwendungen. Doch es gibt mehr zu beachten, als es zunächst scheint. Wenn Sie Ihre Abhängigkeiten im Blick behalten, laufen Ihre Spring-Boot-Projekte reibungslos und sind gegen sich ständig weiterentwickelnde Bedrohungen gewappnet.

Ein wichtiger Aspekt beim Verwalten von Spring-Boot-Abhängigkeiten ist die Sicherheit. Software-Schwachstellen werden häufig entdeckt. Wenn Sie die Abhängigkeiten Ihres Projekts aktuell halten, stärken Sie damit Ihren digitalen Schutz. Veraltete Abhängigkeiten sind wie unverschlossene Türen, die potenzielle Bedrohungen einladen – und genau das möchten wir vermeiden.

Sicherheitslücken in Spring Boot finden

Tools zur Software Composition Analysis (SCA) sind für Entwicklerinnen und Entwickler äußerst hilfreich. Sie erleichtern die Verwaltung von Abhängigkeiten, den Umgang mit Sicherheitslücken, die Klärung von Lizenzfragen und die Einhaltung von Compliance-Vorgaben in Ihren Softwareprojekten. Mit Snyk Open Source als SCA-Lösung finden Sie ganz einfach heraus, ob Ihre Spring-Boot-Pakete Sicherheitslücken enthalten.

In meinem Beispielprojekt habe ich mehrere Sicherheitslücken gefunden. Die erste ist eine schwerwiegende Sicherheitslücke in `netty-codec-http2`. Dabei handelt es sich um eine transitive Abhängigkeit, die von meinem `spring-boot-start-webflux` eingebunden wird, wie Sie unten sehen.

Details zur Sicherheitslücke in io.netty:netty-codec-http2: als Denial-of-Service mit einem Score von 725 eingestuft; empfohlenes Upgrade zur Behebung.

Die zweite Sicherheitslücke, auf die ich eingehen möchte, ist eine mittelschwere Schwachstelle, die eine beliebige Codeausführung ermöglicht und über das Paket `snakeyaml` eingebunden wird. Auch dies ist eine transitive Abhängigkeit, diesmal über `spring-boot-starter-security`.

Schwachstellenbericht für org.yaml:snakeyaml mit beliebiger Codeausführung, Score 405, eingeführt durch Spring Boot Security 2.7.16.

Auf das konkrete Problem der einzelnen Sicherheitslücken gehe ich heute nicht näher ein. Weitere Informationen zum `snakeyaml`-Problem finden Sie in diesem speziellen Blogbeitrag. Konzentrieren wir uns darauf, das Problem zu lösen und die beste Lösung umzusetzen.

Sicherheitslücken in Paketen Ihrer Spring-Boot-Anwendung beheben

Für die erste Sicherheitslücke gibt es eine klare Lösung. Meine Anwendung basiert auf Spring Boot 2.7.16, daher hat auch `spring-boot-starter-webflux` die Version 2.7.16.

Ein Update des Webflux-Starters auf Version 2.7.17 sollte das Problem beheben. Dafür gibt es mehrere Möglichkeiten

– aber nicht alle sind empfehlenswert.

Das Spring-Boot-Manifest sieht normalerweise etwa so aus:

Maven:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.7.16</version>
   <relativePath/>
</parent>
…
<dependencies>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-webflux</artifactId>
   </dependency>
  …
</dependencies>

Gradle:

plugins {
 …
 id 'org.springframework.boot' version '2.7.16'
 id 'io.spring.dependency-management' version '1.1.3'
}
…
dependencies {
 implementation 'org.springframework.boot:spring-boot-starter-security'
 implementation 'org.springframework.boot:spring-boot-starter-webflux'
 …
}

Spring-Boot-Starter aktualisieren

Die Versionsnummern der einzelnen `spring-boot-starters` leiten sich vom `spring-boot-starter-parent` (Maven) oder vom Plugin `org.springframework.boot` in Gradle ab. 

Der Hauptgrund dafür ist, dass all diese Starter-Pakete zur selben Spring-Version gehören und als solche getestet werden.

Für die erste Sicherheitslücke in meinem Projekt wird als Lösung vorgeschlagen, `spring-boot-starter-webflux` auf Version 2.7.17 zu aktualisieren. Damit soll die schwerwiegende Sicherheitslücke behoben werden. Das legt nahe, dass ich nur das Webflux-Paket aktualisieren muss. Dazu könnte ich eine bestimmte Version festlegen, wie unten gezeigt.

Maven:

   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-webflux</artifactId>
       <version>2.7.17</version>
   </dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-webflux:2.7.17'

Aber halt! Dies ist nicht der empfohlene Weg, das Problem zu lösen. Die angegebene Version 2.7.17 wird gegenüber der übergeordneten Version verwendet. Da es sich um ein Patch-Release handelt, funktioniert das möglicherweise. Es ist jedoch nicht die beste oder sicherste Lösung.  Da Semver nicht garantiert, dass APIs unverändert bleiben, können wir nicht sicher sein, dass dies funktioniert. Noch wichtiger ist aber, dass es wahrscheinlich bereits ein neues Spring-Boot-Release gibt.

Denken Sie daran, dass diese Starter zusammengehören. Am besten aktualisieren Sie daher Ihre gesamte Spring-Boot-Distribution auf Version 2.7.17. Das ist bei Minor- oder Major-Releases eines Pakets besonders wichtig, da diese die API beeinträchtigen und dazu führen können, dass die Pakete nicht reibungslos zusammenarbeiten. Gehen Sie in diesem Beispiel also wie folgt vor: Aktualisieren Sie das Parent (Maven) oder das Plugin (Gradle), anstatt einzelne Starter zu aktualisieren.

Maven:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.7.17</version>
   <relativePath/>
</parent>

Gradle:

plugins {
 …
 id 'org.springframework.boot' version '2.7.17'
}

Ich empfehle allen, noch einen Schritt weiterzugehen und die gesamte Spring-Boot-Version auf die neueste geeignete Version zu aktualisieren. Welche das ist, erfahren Sie ganz einfach unter https://start.spring.io.

Spring-Initializr-Oberfläche mit Auswahlmöglichkeiten für Projekt, Programmiersprache und Spring-Boot-Version. Ausgewählt sind Gradle-Groovy, Java und Spring Boot 2.7.17.

Transitive Abhängigkeiten aktualisieren

Bei der zweiten Sicherheitslücke hat Snyk festgestellt, dass es in meiner Anwendung keine eindeutige Empfehlung zur Behebung gibt. Derzeit ist auch keine Version eines `spring-boot-starter` verfügbar, die diese unsichere transitive Abhängigkeit nicht enthält. Wir wissen jedoch, dass eine aktualisierte Version der transitiven Abhängigkeit verfügbar ist. Ein Update auf `snakeyaml` 2.0 behebt das Problem.

Noch einmal: Dies ist nur ein Beispiel. Möglicherweise ist bereits eine aktualisierte Version eines `spring-boot-starter` verfügbar, wenn Sie dies lesen. Prüfen Sie das also unbedingt. Weitere Informationen zur SnakeYaml-Sicherheitslücke finden Sie in unserem speziellen Blogbeitrag zu diesem Thema.

Versionsparameter aktualisieren

Prüfen Sie zunächst, ob die Version des Pakets, das Sie aktualisieren möchten, in Spring Boot als Property festgelegt ist. Die Spring-Boot-Dokumentation enthält einen Anhang mit den Abhängigkeitsversionen für das jeweilige Release. Dort finden Sie auch die Versionseigenschaften. Diese Properties lassen sich sowohl in Maven als auch in Gradle überschreiben, sodass eine neuere Version der transitiven Abhängigkeit verwendet wird. 

In Maven können Sie im Abschnitt „properties“ eine Property hinzufügen.

<properties>
   <snakeyaml.version>3.0</snakeyaml.version>
</properties>

In Gradle können wir diese Property in einer Datei `gradle.properties` bearbeiten:

snakeyaml.version=3.0

Dies ist die bevorzugte Methode gegenüber dem Dependency Management, da `snakeyaml` nur eine einzelne Bibliothek ist. In vielen Fällen handelt es sich jedoch um mehrere Bibliotheken. Die Version kann sich auf eine BOM (Bill of Materials) beziehen – nicht zu verwechseln mit einer SBOM. Sie umfasst eine Gruppe von Paketen, die gemeinsam verwendet werden müssen und im Wesentlichen dieselbe Version haben, etwa ein API- und ein Implementierungspaket. Damit sie wie erwartet funktionieren, müssen beide dieselbe Version verwenden.

Dependency-Management-Deklaration

Alternativ können Sie die Mechanismen Ihres Build-Tools verwenden, um transitive Abhängigkeiten zu aktualisieren. Nutzen Sie diese Möglichkeit nur, wenn Sie die Property-Version nicht wie im vorherigen Abschnitt beschrieben aktualisieren können.

In Maven wird dies meist im Block `dependencyManagement` hinzugefügt. Dadurch wird sichergestellt, dass die dort angegebene aktualisierte Version jedes Mal verwendet wird, wenn die Bibliothek als transitive Abhängigkeit eingebunden wird.

Maven:

<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.yaml</groupId>
           <artifactId>snakeyaml</artifactId>
           <version>2.2</version>
       </dependency>
   </dependencies>
</dependencyManagement>

Da wir in unserer Gradle-Datei das dependency-management-Plugin für Spring verwenden, stehen uns in Gradle sehr ähnliche Funktionen zur Verfügung. Beachten Sie, dass dieses Plugin beim Erstellen meines Projekts vom Spring-Boot-Initializer eingefügt wurde.

Gradle:

dependencyManagement {
   dependencies {
       dependency 'org.yaml:snakeyaml:2.2'
   }
}

Wenn Sie das Plugin `io.spring.dependency-management` nicht verwenden, können Sie in Gradle auch Constraints für transitive Abhängigkeiten hinzufügen, um eine solche Abhängigkeit wie unten gezeigt zu aktualisieren. Beachten Sie, dass diese Constraints nicht gut mit dem Spring-Plugin `dependency-management` zusammenspielen. Sie müssen sich also für eine der beiden Optionen entscheiden.

dependencies {
    …
    constraints {
        implementation('org.yaml:snakeyaml:2.2') {
            because 'previous versions have a security issue'
        }
    …
}

Spring-Boot-Anwendungen mit Snyk scannen

Das Scannen Ihrer Spring-Boot-Anwendung mit Snyk ist entscheidend für die Sicherheit und Stabilität Ihrer Software. Snyk hilft Ihnen dabei, Sicherheitslücken in den Abhängigkeiten Ihrer Anwendung zu erkennen, die von Angreifern ausgenutzt werden könnten, wenn sie nicht behoben werden. Nach der Lektüre dieses Artikels wissen Sie auch, wie Sie die von Snyk empfohlenen Maßnahmen am besten umsetzen.

Durch regelmäßige Scans Ihrer Codebasis können Sie Sicherheitsprobleme proaktiv angehen und das Risiko von Datenschutzverletzungen und anderen Sicherheitsvorfällen senken. Integrieren Sie Scans also in Ihren regulären Workflow und stellen Sie sicher, dass Sie wissen, wie Sie im Fall einer Sicherheitslücke reagieren müssen.

Unten habe ich meine Anwendung vor und nach der Behebung mit der Snyk CLI gescannt. Zur Behebung habe ich die allgemeine Spring-Boot-Version aktualisiert und die spezifische Versionseigenschaft für `snakeyaml` angepasst.

Vorher:

Terminalausgabe mit den Ergebnissen eines Snyk-Scans für Spring-Boot-Abhängigkeiten, darunter 14 Probleme und 21 verwundbare Pfade.

Nachher:

Die Terminalausgabe meldet: 98 Abhängigkeiten getestet, 3 Probleme gefunden und 6 anfällige Pfade, darunter RCE- und Zertifikatsvalidierungsschwachstellen.

Wenn Sie also mit Snyk eine Sicherheitslücke in einer Abhängigkeit Ihrer Spring-Boot-Anwendung finden, gehen Sie folgendermaßen vor:

  • Aktualisieren Sie die allgemeine Spring-Boot-Version, anstatt nur einen bestimmten Starter zu aktualisieren.

  • Wenn Sie die Spring-Boot-Version aktualisieren, reicht es nicht aus, nur die Versionseigenschaften der Spring-Boot-Abhängigkeiten zu aktualisieren.

  • Verwenden Sie Dependency Management in Maven oder Gradle, um bestimmte transitive Abhängigkeiten zu aktualisieren.

Starten Sie mit Capture-the-Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Challenges lösen.

Weiterlesen

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.

feature insights context
Blog

Autonome Angriffe sind bereits Realität. Die Verteidigung muss Schritt halten.

Autonome Angreifer verkürzen das Zeitfenster für die Verteidigung. Erfahren Sie, wie kontinuierliches Erkennen, Beheben, Validieren und Verhindern Sicherheitsteams helfen kann, Schritt zu halten.

Blog

Warum KI-Coding-Agenten immer wieder fehlerhafte Zugriffskontrollen schreiben

KI-Coding-Agenten können Autorisierungslogik erzeugen, die kompiliert und die Prüfung besteht, dabei aber die Daten eines Mandanten für einen anderen offenlegt. Erfahren Sie, warum fehlerhafte Zugriffskontrollen schwer zu erkennen sind und wie Sie sie verhindern.