Der Original-Artikel aus der „Java aktuell“ steht hier als PDF zum Download bereit.
Einen Überblick über die häufigsten Makel in Punkto Sicherheit bietet die Top Ten des Open Web Application Security Project (OWASP), eine Non-Profit-Organisation, die sich zum Ziel gesetzt hat, die Sicherheit in Web zu verbessern. Hier zeigt sich zudem, dass auch nicht selbst geschriebener Code Sicherheitslücken enthalten kann. Diesen kann man jedoch mit wenigen Schritten überprüfen. Dieser Artikel zeigt, wie man mit geringem Aufwand zumindest über die bekannten Sicherheitslücken in verwendeten Abhängigkeiten von Dritten auf dem Laufenden bleibt.
Grundlage bildet die National Vulnerability Database (NVD) eine Art Datenbank für Sicherheitslücken. Sie wird gepflegt vom National Institute of Standards and Technology (NIST), eine mit der deutschen Physikalisch-Technische Bundesanstalt (PTB) vergleichbare US-amerikanische Bundesbehörde, die auch bekannte Verschlüsselungsalgorithmen wie DES und AES standardisiert.
Die NVD beinhaltet unter anderem die Schwachstellen, die im Industrie-Standard „Common Vulnerabilities and Exposures“ (CVE) erfasst werden. Die bereits erwähnte OWASP bietet eine Anwendung an, die automatisiert Jar-Dateien mit der NVD abgleicht. Dieser sogenannte „OWASP Dependency-Check“ (DChck) wurde für die Kommandozeile sowie für Ant, Maven, gradle, sbt, Jenkins und SonarQube implementiert.
Nachfolgend ein Lösungskonzept, um die Abhängigkeiten einer Java-Anwendung mithilfe von Maven und Jenkins regelmäßig auf neue Sicherheitslücken zu durchsuchen. Nach einmaliger Einrichtung sind keine weiteren Schritte notwendig. Die Information über neu gefundene Sicherheitslücken erfolgt dann per E-Mail. Dabei kann es sich entweder um neu bekannt gewordenen Sicherheitslücken in bestehenden Abhängigkeiten handeln oder um bereits bekannte Sicherheitslücken, die in neu hinzugefügten Abhängigkeiten existieren.
Erster Schritt: Maven-Plug-in ohne Konfiguration verwenden
Eine erste Überprüfung der Abhängigkeiten der eigenen Anwendung kann ohne weitere Konfiguration in wenigen Sekunden angestoßen werden, beispielsweise mittels Maven-Plug-in (MVN) durch mvn org.owasp:dependency-check-maven:1.4.0:aggregate
.
Dabei gilt es zu beachten, dass „dependency-check-maven-plug-in“ zunächst eine lokale Kopie der CVE-Datenbank in Form einer H2 Datenbank herunterlädt und sie im lokalen Maven-Repository speichert. Aufgrund der Anzahl bekannter Sicherheitslücken resultiert dies in einer mehrere Hundert Megabytes umfassenden Datei. Das initiale Erzeugen kann, abhängig von verfügbarer Bandbreite und Rechenleistung, einige Minuten dauern. Nach erfolgreichem Abschluss befindet sich der Bericht unter „target/dependency-check-report.html“. Ein Beispiel für einen solchen Bericht findet man auf der Website des Projekts (DChck-Sample).
Automatisierung mit Jenkins
Um ohne weiteres Zutun über neu gefundene Sicherheitslücken informiert zu werden, bietet sich eine regelmäßig durchgeführte, automatische Überprüfung an. OWASP bietet für den CI-Server Jenkins ein Plug-in in an, das die Überprüfung durchführen und deren Ergebnisse auswerten kann. Unter anderem können die gefundenen Sicherheitslücken in Jenkins visualisiert, das Ergebnis eines Jobs von der Anzahl gefundener Sicherheitslücken abhängig gemacht und die Entwicklung der Anzahl gefundener Sicherheitslücken über die Builds in einem Diagramm dargestellt werden. Diese Auswertung wird in einer Post-Build-Action im Jenkins-Job konfiguriert. Die Überprüfung der Abhängigkeiten selbst kann durch einen durch das Jenkins-Plug-in bereitgestellten Build-Step oder per Maven durchgeführt werden.
Da die Überprüfung einige Zeit in Anspruch nimmt, sollte sie nicht bei jedem Commit/Push stattfinden. Ein Nightly-Build oder ein einmal pro Woche durchgeführter Build bieten sich daher an. Die Überprüfung per Maven Goal statt mit Jenkins-Build Step hat den Vorteil, dass die zentrale Konfiguration in der pom.xml
erfolgt, wie in Listing 1 gezeigt.
<properties>
<dependency-check-format>HTML</dependency-check-format>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>1.4.0</version>
<configuration>
<format>${dependency-check-format}</format>
</configuration>
</plugin>
</plugins>
</build>
Listing 1: Maven Konfiguration mit parameterisierbarem Format des Reports
Mit dieser Konfiguration müssen in Jenkins nur noch die folgenden Maven Goals mit Parameter aufgerufen werden:
mvn clean install org.owasp:dependency-check-maven:check -Ddependency-check-format=XML
.
Dadurch wird eine Datei target/dependency-check-report.xml
im Workspace generiert, die man in von einer entsprechenden Post-Build-Action verarbeiten lassen kann. Abschließend muss in dieser noch konfiguriert werden, dass der Job fehlschlägt oder instabil wird, sobald eine Sicherheitslücke entdeckt wird (siehe Abbildung). In Zusammenarbeit mit der von Jenkins angebotenen E-Mail-Benachrichtigung ist sichergestellt, dass man ohne weiteres Zutun per E-Mail über neu gefundene Sicherheitslücken informiert wird.
Die Praxis
Abschließend noch einige Details, die in der täglichen Arbeit mit dem Dependency-Check relevant sein können.
Es empfiehlt sich, den Dependency-Check auf dem Maven-Modul durchzuführen, das das eigentlich veröffentlichte Artefakt (.jar, .war, .ear etc.) herstellt. Dadurch werden auch nur die wirklich relevanten Abhängigkeiten auf Sicherheitslücken durchsucht und nicht die Abhängigkeiten von Modulen, die beispielsweise nur für Tests im Einsatz sind. Abhängigkeiten im Maven-Scope-Test werden in der aktuellen Version des Maven-Plug-ins standardmäßig nicht durchsucht.
Anders sieht es mit Abhängigkeiten in den Scopes provided
und runtime
aus. Insbesondere bei provided
können sie unerwünscht sein. Wenn man beispielsweise durch die Kundenumgebung an ein bestimmtes Servlet-API gebunden ist, ist man gegen die gegebenfalls darin enthaltenen Sicherheitslücken machtlos. Insofern kann es durchaus sinnvoll sein, diesen Scope auszuschließen. Dies kann in der Konfiguration von Maven angepasst werden (siehe Listing 2).
Alternativ lassen sich bestimmte CVEs auch für einzelne Abhängigkeiten unterdrücken. Diese sind in einer speziellen Datei spezifiziert. Der XML-Code für das Unterdrücken lässt sich direkt aus dem im ersten Schritt generierten HTML-Bericht kopieren. Dies kann insbesondere sinnvoll sein, wenn es sich um False Positives handelt, also um gefundene Sicherheitslücken, die auf die Abhängigkeit gar nicht zutreffen. Ein Beispiel dafür ist der Generalverdacht (CVE-2016-3270) gegen alle Module des Jackson-Frameworks, obwohl nur in einem eine Sicherheitslücke auftritt. Es ist daher generell sinnvoll, jede gefundene Sicherheitslücke auf Korrektheit zu überprüfen. In jedem Fall sollte kommentiert werden, weshalb ein CVE unterdrückt wird, um zu späteren Zeitpunkten die Gründe für den Ausschluss nachvollziehen zu können. In den Listings 2 und 3 wird diese Möglichkeit für den Ausschluss aufgezeigt.
<configuration>
<!-- Skip artifacts not bundled in distribution (provided scope) -->
<skipProvidedScope>true</skipProvidedScope>
<!-- Suppress false positives or dependencies that cannot be changed for specific reasons.-->
<suppressionFile>suppress-cves.xml</suppressionFile>
</configuration>
Listing 2: Maven Konfiguration mit suppressionFile und provided Scope
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
<suppress>
<!-- This Jackson-related issue seems to be related to module jackson-dataformat-xml, which is not used here. It is considered a false positive. See https://github.com/jeremylong/DependencyCheck/issues/517 In addition it was fixed in version 1.7.4., see https://github.com/FasterXML/jackson-dataformat-xml/issues/199 -->
<notes><![CDATA[file name: jackson-core-2.8.1.jar]]></notes>
<sha1>fd13b1c033741d48291315c6370f7d475a42dccf</sha1>
<cve>CVE-2016-3720</cve>
</suppress>
<suppress>
<!-- Same as other Jackson-related issue -->
<notes><![CDATA[file name: jackson-annotations-2.8.0.jar]]></notes>
<sha1>45b426f7796b741035581a176744d91090e2e6fb</sha1>
<cpe>cpe:/a:fasterxml:jackson:2.8.0</cpe>
</suppress>
</suppressions>
Listing 3: Beispielhaftes suppressionFile
Fazit
Der Artikel beschreibt wie man mit wenigen Schritten dauerhaft über bekannte Sicherheitslücken von Abhängigkeiten informiert bleibt. Dies sorgt nicht für absolute Sicherheit, entschärft aber mit geringem Aufwand einen der zehn gängigsten Makel. Insofern ist dies uneingeschränkt für alle Java-Projekte zu empfehlen.
Die hier beschriebene, auf Maven und Jenkins basierende Lösung stellt eine Möglichkeit für das Herausfinden von Sicherheitslücken dar. Aufgrund der vielen verfügbaren Implementierungen des OWASP-Dependency-Checks lassen sich vergleichbare Lösungen auch für viele andere Tools realisieren.
Ein komplett lauffähiges Beispiel, das die oben beschriebenen Fälle sowie eine Abhängigkeit mit nicht ausgeschlossener Sicherheitslücke enthält, steht bei GitHub.
