Skip to main content

Best Practices für die Verwaltung von Java-Abhängigkeiten

Artikel von
hero presentation

26. August 2022

0 Min. Lesezeit

Java-Anwendungen zu entwickeln, macht Spaß, und es stehen zahlreiche Ressourcen zur Verfügung. Um die Entwicklung zu beschleunigen, verwenden viele Entwickler Frameworks und Bibliotheken, die ihnen einen Großteil der Arbeit abnehmen. Betrachtet man moderne Java-Anwendungen, enthalten fast alle Abhängigkeiten von Bibliotheken, die von anderen entwickelt wurden.

Abhängigkeiten machen etwa 80 bis 90 Prozent der Binärdatei aus – deshalb sollten wir sorgfältig mit ihnen umgehen, wenn wir ein Java-Projekt erstellen. In diesem Artikel gebe ich Ihnen Tipps und Best Practices für den Umgang mit Java-Abhängigkeiten in Ihrem Projekt.

Warum Sie Ihre Java-Abhängigkeiten besser im Blick behalten sollten

Bei der Verwaltung von Code-Beiträgen setzen wir in der Regel auf ein Verfahren wie Code-Reviews, um die Qualität zunächst zu prüfen, bevor neuer Code in unseren Hauptbranch übernommen wird. In unserem Leitfaden zu Java-Code-Review-Tools erfahren Sie mehr. Pair Programming ist eine weitere Möglichkeit, diesen Qualitätssicherungsprozess abzudecken.

Der Umgang mit Abhängigkeiten unterscheidet sich jedoch deutlich von unserem Umgang mit eigenem Code. Oft werden Abhängigkeiten ohne jegliche Prüfung verwendet. Zudem ziehen direkte Abhängigkeiten häufig transitive Abhängigkeiten nach sich, die sich über mehrere Ebenen erstrecken können. Eine 200 Zeilen lange Spring-Anwendung mit fünf direkten Abhängigkeiten kann beispielsweise insgesamt 60 Abhängigkeiten nutzen. Das entspricht fast einer halben Million Codezeilen, die in die Produktion gelangen.

Java-Abhängigkeiten in Legacy-Projekten zu aktualisieren, kann eine Herausforderung sein. Sind sie veraltet, kann es zu einem Dominoeffekt von Kompatibilitätsproblemen kommen. Ein Update einer einzelnen Bibliothek kann mehrere weitere Updates erforderlich machen – etwa aufgrund eines Fehlers oder Sicherheitsproblems. Ändern diese Java-Abhängigkeiten ihre API, müssen Sie möglicherweise Ihre gesamte Anwendung umschreiben.

Außerdem bleiben Abhängigkeiten in vielen großen Unternehmensanwendungen in der Manifestdatei, selbst wenn der Code sie nicht mehr verwendet. Diese ungenutzten Abhängigkeiten sind weiterhin in Ihrem Programm verfügbar.

All das kann zu Folgendem führen:

  • Größere Binärdateien, die mehr Ressourcen beanspruchen oder längere Startzeiten verursachen

  • Mögliche Konflikte zwischen Bibliotheken, wenn neue Abhängigkeiten hinzugefügt werden

  • Veraltete Bibliotheken mit Fehlern oder Sicherheitsproblemen

  • Kompatibilitätsprobleme beim Aktualisieren von Bibliotheken

  • Und mehr

Java-Abhängigkeiten verwalten

Eine der Best Practices für die umfassende Nutzung von Repositories wie Maven Central ist die Einrichtung eines eigenen Repository-Managers. Dabei handelt es sich um einen dedizierten Proxy-Server zwischen Ihrer internen Entwicklungsumgebung und öffentlichen Repositories. Er sorgt nicht nur für schnellere und stabilere Builds, sondern ermöglicht Ihnen auch, Richtlinien für Java-Pakete festzulegen. Sie können beispielsweise bestimmte Versionen sperren, damit sie nicht heruntergeladen und in Ihren Anwendungen verwendet werden können.

Weitere Informationen zu Repository-Managern und eine Liste möglicher Produkte finden Sie in der Maven-Dokumentation.

Neue Abhängigkeiten in Ihr Java-Projekt aufnehmen

Wenn Sie ein Problem lösen müssen und dafür eine Bibliothek verfügbar ist, möchten Sie sie wahrscheinlich in die Manifestdateien Ihrer Java-Abhängigkeiten aufnehmen. Bevor Sie das tun, sollten Sie jedoch Folgendes bedenken:

Löst sie das Problem?

Der Hauptgrund für den Import eines Pakets ist, ein Problem zu lösen. Die Frage ist, ob die von Ihnen gewählte Abhängigkeit das leisten kann. Löst sie außerdem das gesamte Problem, ohne neue Herausforderungen mit sich zu bringen? Wenn nicht, gibt es möglicherweise bessere Lösungen.

Benötige ich das gesamte Paket?

Lohnt es sich, eine umfangreiche Abhängigkeit mit vielen Funktionen und Datentypen zu importieren, wenn Sie nur eine einzige Funktion benötigen? Manchmal ist es einfacher und besser zu verwalten, diese Funktion selbst zu schreiben. Ist es beispielsweise sinnvoll, Eclipse Collections komplett einzubinden, wenn Sie nur den Datentyp Tuple verwenden möchten? Wahrscheinlich nicht.

Ein kurzer Blick auf mvnrepository.com zeigt, dass dieses Paket etwa 10 MB groß ist.

MvnRepository-Seite für Eclipse Collections Main Library Version 11.1.0 mit Lizenz, Tags, Dateien, Repository, Rankings und Nutzung.

Prüfen Sie außerdem, ob die Abhängigkeiten, die Sie bereits verwenden, die Aufgabe erledigen können. Möglicherweise stehen ähnliche Funktionen oder Datentypen bereits zur Verfügung. Andererseits kann eine neue, umfangreiche Bibliothek Ihnen dabei helfen, mehrere Probleme auf einmal zu lösen – es kommt ganz auf die Situation an.

Wie viele Mitwirkende gibt es?

Wenn die von Ihnen verwendete Java-Abhängigkeit nur einen oder wenige Maintainer hat, ist ihr Bus-Faktor ziemlich niedrig. Was passiert, wenn der Maintainer aufhört oder keine Zeit hat, einen Fehler zu beheben? Sie können sich alternativ auch selbst am Projekt beteiligen – und es so für alle Beteiligten sicherer machen.

Bevor Sie Abhängigkeiten in Ihr Projekt aufnehmen, sollten Sie jedoch das zentrale Repository prüfen und herausfinden, wie viele Maintainer aktiv sind.

GitHub-Repository-Header mit 1.173 Commits, 10 Branches, 0 Paketen, 40 Releases und 66 Mitwirkenden

Wird das Paket noch gepflegt?

Wenn ein Paket nicht mehr gepflegt wird, sollten Sie sich keinesfalls darauf verlassen. Prüfen Sie vor der Integration eines Pakets, ob es neue Commits im GitHub-Repository gibt, und sehen Sie sich den Release-Zyklus an. So können Sie einschätzen, wie gut das Paket gepflegt wird.

Repository-Oberfläche mit einem Commit von vor 2 Stunden, markiert durch einen pinkfarbenen Pfeil, darunter zwei aufgelistete Ordner

Was ist die neueste Paketversion?

Codebeispiele können Ihnen wertvolle Einblicke in eine bestimmte Java-Abhängigkeit geben. Sie sind jedoch möglicherweise veraltet, und das betreffende Paket wurde vielleicht bereits aktualisiert. Ziehen Sie die neueste stabile Version in Betracht. Für Eclipse Collections ist laut mvnpackage.com die neueste stabile Version 11.1.0 vom 5. Juli 2022. Verwenden Sie am besten diese Version.

Beachten Sie, dass in dieser Abbildung auch 11.1.0.M2 aufgeführt ist. Dabei handelt es sich eindeutig um eine Vorabversion. Verwenden Sie in Ihrer Produktionsanwendung nur stabile Releases, es sei denn, Sie sind sich absolut sicher. Als Faustregel gilt: Nehmen Sie keine Versionen mit einem Qualifier auf, zum Beispiel:

  • alpha oder a

  • beta oder b

  • milestone oder m

  • rc oder cr

  • snapshot

Hat eine Java-Abhängigkeit den Qualifier GA oder final, können Sie sie in der Regel als stabile Version betrachten.

Tabelle mit Java-Versionen, Anzahl der Schwachstellen, Links zum Central-Repository, Nutzungszahlen und Veröffentlichungsdaten.

Gibt es bekannte Sicherheitslücken?

Bevor Sie sich auf ein Java-Paket verlassen, sollten Sie es auf bekannte Sicherheitslücken überprüfen. Die Snyk CLI eignet sich hervorragend, um Ihre Maven- oder Gradle-Datei zu scannen. Enthält Ihre Bibliothek eine Sicherheitslücke, sollten Sie möglicherweise ein anderes Paket verwenden.

Java-Abhängigkeiten aktualisieren

Sind neuere Versionen verfügbar?

Sie möchten sicher nicht jede Ihrer Java-Abhängigkeiten manuell daraufhin prüfen, ob neuere Versionen verfügbar sind. Zum Glück gibt es einfachere Möglichkeiten. Mit Plugins für Ihren Paketmanager können Sie Ihre Abhängigkeiten so oft wie gewünscht automatisch überprüfen lassen – zum Beispiel bei jedem Build.

Beachten Sie, dass Ihre Tools möglicherweise Beta- oder Vorabversionen vorschlagen. Es wird dringend empfohlen, nur stabile Versionen einer Bibliothek zu verwenden.

Maven-Beispiel

In Maven können Sie wie unten gezeigt das Versions-Plugin verwenden. Sie müssen nichts Besonderes in Ihre pom.xml eintragen.

mvn versions:display-dependency-updates
Terminalausgabe des Maven Versions Plugin listet verfügbare Dependency-Updates auf und zeigt einen erfolgreichen Build.

Gradle-Beispiel

Für Gradle müssen wir ein Plugin einbinden, zum Beispiel das Versions-Plugin von ben-manes.

plugins {
  id "com.github.ben-manes.versions" version "0.42.0"
}

Nun können wir einen ähnlichen Befehl ausführen, um neuere Versionen Ihrer Bibliotheken anzuzeigen.

gradle dependencyUpdates -Drevision=release
Terminalausgabe mit dem Titel „Projektabhängigkeitsaktualisierungen“, die Java-Abhängigkeiten mit aktuellen und späteren Release-Versionen auflistet.

IntelliJ IDEA

Wenn Sie IntelliJ IDEA verwenden, werden aktualisierbare Abhängigkeiten unterstrichen. Das funktioniert sowohl bei Maven- als auch bei Gradle-Projekten.

Java-Maven-Abhängigkeits-XML mit org.eclipse.collections und einer IDE-Aufforderung, eclipse-collections-api von Version 10.3.0 auf 11.1.0 zu aktualisieren.

Snyk

Wenn Sie Ihr GitHub-Repository mit Ihrem Snyk-Konto verbinden, erhalten Sie bei jedem Pull Request empfohlene Fixes oder Updates. Zusammen mit unseren umfassenden Sicherheitsempfehlungen hilft Ihnen das dabei, Ihre Java-Abhängigkeiten auf dem neuesten Stand zu halten.

GitHub-Pull-Request von Snyk, der ein Upgrade von org.eclipse.collections:eclipse-collections von Version 10.3.0 auf 11.1.0 vorschlägt.

Werden die von Ihnen verwendeten Pakete noch gepflegt?

Es ist sinnvoll, das GitHub-Repository oder mvnpackage.com erneut aufzurufen, um nach aktuellen Updates und Commits zu suchen. Scheint ein Paket nicht mehr ausreichend gepflegt zu werden, können Sie es selbst betreuen oder zu einer besser gepflegten Bibliothek wechseln.

Wenn Sie jedoch auf ein Problem mit einer für Ihre Anwendung kritischen Abhängigkeit stoßen, sollten Sie das Problem selbst beheben und den Fix zum Open-Source-Projekt beitragen. Das wird sehr geschätzt – und ist oft schneller, als Fehlerberichte einzureichen und den Maintainer zur Behebung des Problems zu bewegen.

Gibt es Sicherheitsprobleme mit meinen Java-Abhängigkeiten?

Auch wenn Ihre Anwendung aktuell keine Sicherheitslücken aufweist, muss das nicht für immer so bleiben. Täglich werden neue Sicherheitslücken und Exploits entdeckt und offengelegt. Deshalb müssen Sie Ihre Bibliotheken regelmäßig erneut scannen, um sicherzustellen, dass sie weiterhin keine bekannten Sicherheitslücken enthalten.

Snyk bietet Ihnen verschiedene Möglichkeiten, das Scannen von Abhängigkeiten in Ihren Entwicklungslebenszyklus zu integrieren. Auf Ihrem lokalen Rechner können Sie die Snyk CLI oder die Integrationen für IntelliJ, Eclipse oder VS Code verwenden, um nach Sicherheitslücken zu suchen. Sie können auch während des Build-Prozesses mit dem Maven- und Gradle-Plugin (nicht offiziell) oder über eine der CI-Pipeline-Integrationen scannen. Alternativ können Sie Ihr Git-Repository zu Snyk hinzufügen, damit wir Ihre Projekte täglich für Sie scannen und aktualisieren.

Snyk-Schwachstellenbericht mit kritischen Apache-Struts-Problemen, darunter Befunde zu beliebiger und entfernter Codeausführung mit Schweregradbewertungen.

Java-Abhängigkeiten aus Ihrem Projekt entfernen

Wird das Paket noch verwendet?

Wird eine Java-Abhängigkeit nicht mehr verwendet, sollten wir sie aus unserer Manifestdatei entfernen. Jedes Paket in dieser Datei ist Teil Ihrer Binärdatei und im Classpath verfügbar. Wenn Sie ungenutzte Abhängigkeiten entfernen, wird Ihre Binärdatei kleiner – und startet schneller und lässt sich schneller herunterladen. Außerdem verbessert sich die Sicherheit. Die Anzahl der Abhängigkeiten in Ihrem Classpath zu minimieren, ist entscheidend, um sich vor Angriffen wie einer Deserialisierungs-Gadget-Chain zu schützen.

Eine Clean-Desk-Policy – oder in diesem Fall eine Clean-App-Policy – ist immer sehr empfehlenswert. Zum Glück helfen Ihnen Ihre Paketmanager dabei, ungenutzte Java-Abhängigkeiten zu erkennen.

Maven-Beispiel

Für Maven kann ich das Dependency-Plugin verwenden, um meine Abhängigkeiten zu analysieren. Dieses Plugin prüft, ob die deklarierten Java-Abhängigkeiten auch in meinem Code verwendet werden.

In diesem Fall möchte ich nicht durch Abhängigkeiten mit dem Scope provided oder test gestört werden. Deshalb verwende ich das Flag ignoreNonCompile.

mvn dependency:analyze -DignoreNonCompile
Terminal-Warnung mit nicht verwendeten deklarierten Abhängigkeiten: Apache Commons Lang 3.9 und Apache Struts 2.5.10.

Gradle-Beispiel

In Gradle müssen wir ein weiteres Plugin hinzufügen, um Abhängigkeiten zu analysieren. In diesem Fall verwenden wir das Plugin nebula.lint. Dieser Gradle-Linter kann die von Ihnen eingebundenen Java-Abhängigkeiten analysieren und feststellen, ob Abhängigkeiten ungenutzt sind.

plugins {
   id "nebula.lint" version "17.7.0"
}

Ich muss das Plugin entsprechend konfigurieren, um gradleLint.rules festzulegen. Das können Sie in Ihrer Gradle-Datei oder als Befehlszeilenparameter tun. Im folgenden Beispiel entscheide ich mich für Letzteres. Weitere Informationen zur Konfiguration des Plugins für Ihre Anwendung finden Sie in der Dokumentation.

gradle lintGradle -PgradleLint.rules=unused-dependency
Terminalausgabe mit Lint-Warnungen zu nicht verwendeten Abhängigkeiten von Apache Commons Lang und Struts in build.gradle.

Entwickeln Sie eine solide Strategie für das Abhängigkeitsmanagement Ihrer Java-Anwendungen

Wenn Sie Java-Anwendungen entwickeln und Abhängigkeiten wie Bibliotheken oder Frameworks verwenden, sollten Sie eine Strategie für den Umgang damit festlegen. Zu wissen, wie Sie Java-Abhängigkeiten auswählen, aktualisieren und aus Ihrer Anwendung entfernen, ist für die Sicherheit unerlässlich. Mit einer klaren Strategie vermeiden Sie Überraschungen, wenn ein dringendes Sicherheitsproblem die Aktualisierung eines Pakets erforderlich macht.

In diesem Artikel erfahren Sie mehr über die Verwaltung von Open-Source-Abhängigkeiten.

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 feature snyk container custom base recommendations
Blog

Evo Agentic AppSec: Sicherheit, die mit der KI-Entwicklung Schritt hält

KI-gestützte Entwicklung überholt herkömmliche Security-Workflows. Snyk Agentic AppSec setzt Security-Agenten ein, die Schwachstellen kontinuierlich finden, beheben und überprüfen – während Menschen die Maßstäbe festlegen.

blog feature ai violet
Blog

VulnBump: Können KI-Agenten anfällige Abhängigkeiten beheben, ohne den Build zu beschädigen?

VulnBump testet KI-Agenten anhand von 307 realen Dependency-Upgrades. Eine Lösung zählt nur, wenn die Sicherheitslücke behoben ist und Build sowie Tests weiterhin erfolgreich sind.

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.