Die Log4Shell-Sicherheitslücke in Log4j erschütterte Ende 2021 die IT-Welt. Heute wissen wir, dass Log4Shell zu einem Höchststand bei Cyberangriffen auf Unternehmen geführt hat. Aber darüber hinaus haben wir auch viel für die tägliche Arbeit für unsere Kunden gelernt. In unserem Post-Mortem zur Sicherheitslücke CVE-2021-44228 zeigen wir ein paar Aspekte aus Sicht der Software-Entwicklung auf, über die es sich nachzudenken lohnt.
Gute Kuratoren braucht es
Erkenntnis 1: Kuratoren-Arbeit verdient Anerkennung.
Wir sind froh darüber, hier von der guten Kuratoren-Arbeit des Spring-Teams profitieren zu können und bedanken uns dafür. Alle unsere Anwendungen sind der Spring-Empfehlung zu Logback gefolgt und es waren dort keine Anpassungen notwendig.
Wir entwickeln sehr viele und oft sehr komplexe Anwendungen für und mit unseren Kunden. Seit sehr vielen Jahren tun wir das auf Java-Basis. Zunächst waren wir oft mit unserem eigenen Framework für Business-Anwendungen und Dependency Injection unterwegs. Aus der Zeit erinnere ich mich noch gut an meine Rolle als Kurator der damals noch überschaubaren Menge von Dependencies. Mit zunehmender Verbreitung des Spring-Frameworks, ist es unser präferiertes Java-Framework geworden.
Zunächst war mir das nicht klar, aber damit habe ich die Rolle des Kurators abgegeben. Das Spring-Team bildet das für unsere Anwendungen ab. Mit den "üblichen" Spring-Dependencies kann man den Großteil unserer Business Probleme lösen und darauf vertrauen, dass hier sinnvoll gewählte und zueinander kompatible Bibliotheken zum Einsatz kommen. Diese Kapselungs-Funktion hat das Spring-Team dann immer expliziter gemacht mit dem Spring-Initializr.
Das Vorgehen scheint einen Nerv getroffen zu haben. Das Framework ist dabei durchaus opinionated, lässt aber immer individuelle Anpassungen zu. Solange man den empfohlenen Pfaden gefolgt ist, sind Updates von Spring-Versionen im Allgemeinen sehr reibungslos. Das führt dazu, dass diese Updates auch tatsächlich stattfinden.
Homogenität spart Zeit und Risiken ein
Erkenntnis 2: Nach Vorfällen wie diesem ist der Wert von Homogenität in einer Landschaft von Individual-Anwendungen neu zu bewerten.
Homogenität von Bibliotheken ist erst einmal wünschenswert, um die Angriffsfläche klein zu halten und ein sinnvolles Wissensmanagement betreiben zu können. Sie ist auch mit Mitteln, wie bspw. einem zentralisiertem Dependency-Management (Parent POM) oder dem Enforcer-Plugin zu erreichen, steht aber den Bedürfnissen individueller Teams ggf. mehr im Weg als ein Beschluss, dem "Spring Way" zu folgen – das ist bei Bedarf auch mit unterschiedlichen Geschwindigkeiten möglich.
Wichtiger als die Homogenität der konkreten Bibliotheken und deren Versionen war für uns die Homogenität der Build-Prozesse bei uns und unseren Kunden. Oft war es sehr schnell möglich, abgesicherte Versionen herauszugeben und zu installieren. In einigen Fällen bei unseren Kunden auch deutlich schneller, als etablierte Prozesse das üblicherweise zugelassen hätten. Das stärkt agiles Selbstbewusstsein.
Auf der Detail-Ebene einzelner Bibliotheken fallen die wichtigen Entscheidungen: Eine neue Bibliothek zusätzlich in ein Projekt aufzunehmen kann einfacher sein, als die Recherche nach einer bestimmten Funktion im schon existierenden Baum-Bündel von Bibliotheken. Es braucht aber eine gute Rechtfertigung dafür: Jede zusätzliche Bibliothek impliziert eine Wette auf deren Sicherheit und Stabilität über lange Zeiträume.
Das Management dieser "Wette" verdient mehr Aufmerksamkeit. Wir werden zusätzlich Werkzeuge wie bspw. https://dependencytrack.org/ konsequenter nutzen, um auf diese Weise eine dynamische Inventur von im Einsatz befindlichen Dependencies entstehen zu lassen, die nicht nur ad hoc Transparenz herstellen, sondern auch eine Rückschau zulassen: Wo und von wann bis wann waren verwundbare Dependency-Versionen in Verwendung?
Auch Software-Monokulturen brauchen Pflege
Erkenntnis 3: Homogenität allein wird uns nicht retten.
Sie stellt sogar selbst im Sinne einer Software-Monokultur ein Risiko bei Vorfällen dieser Art dar und sie begrenzt potenziell die Innovationsfähigkeit von Unternehmen. Wer sich auf eine Monokultur-Strategie einlässt hebt damit auch die Ansprüche an die Kuratoren und an die Qualität der transitiven Abhängigkeiten, an die man sich damit "hängt".
Dass die Wartung von Open Source-Komponenten in Architekturen dieser Art von zu wenigen Personen abhängt, die zu wenig Wertschätzung erhalten ist ein offensichtlich ein Problem. Dass sie dabei faktisch mit staatlichen Akteuren konkurrieren müssen, ist beunruhigend. Hier gilt es, als Nutzer:innen-Community für Open Source-Komponten Beiträge zu leisten und stabile Strukturen herzustellen, welche die Resilienz solcher Komponenten als originäres Ziel und ohne wirtschaftliche Interessen verfolgen.
Manuell ist fahrlässig
Erkenntnis 4: Ein Dependency-Management ohne Testautomatisierung und Automatismen wie bspw. den Dependa-Bot auf Github oder entsprechende Werkzeuge für andere Code-Repositories ist aufgrund der Tiefe üblicher Dependency-Bäume nicht mehr verantwortungsvoll möglich bzw. muss als fahrlässig bezeichnet werden.
Werkzeuge dieser Art bereiten den Patch mit der rettenden Versions-Anpassung selbst als Merge-Request vor, führen Tests aus und brauchen nur idealerweise noch eine Freigabe bis zur Erstellung einer abgesicherten Version. Auch ein automatisches akzeptieren dieser Korrekturen ist vorstellbar.
Im konkreten Fall hat das für alle unsere nicht-Spring-Projekte, deren Quellcodes wir auf Github selbst verantworten, exzellent funktioniert. Das Github-Team selbst hat sehr schnell reagiert und die ganze Community profitierte davon.
Defense in Depth
Erkenntnis 5: Defense in Depth funktioniert.
Die Idee dahinter ist die gleiche, wie bei mittelalterlichen Burgen: Hinter dem Wassergraben kommt die Burgmauer – oder vielleicht auch mehrere. Wir verlassen uns nicht auf einen Sicherheitsmechanismus, sondern staffeln diese hintereinander.
Im konkreten Szenario Log4Shell war zu sehen:
- Web Application Firewalls mussten sich in diesem Fall auf ein Katz-und-Maus-Spiel mit veränderlichen Patterns einlassen. Sie haben bestimmt viele Angriffe vereitelt, aber eben nicht zuverlässig.
- Anwendungen mit minimalen Rechten und in "Sandkästen" zu betreiben ist immer eine gute Idee. Viele Angriffe werden hier "versandet" sein. Aus einer kompromittierten Maschine ist im Idealfall wenig zu holen.
- Mit einem Deployment-Szenario bspw. im Kubernetes oder OpenShift lässt sich der Netzwerkverkehr von Anwendungen feingranular steuern. Business-Anwendungen müssen nichts aus dem freien Internet nachladen. Mit diesem "Burggraben" kann Log4Shell effektiv gestoppt werden.
Nur ein kleiner Teil dieser Strategie ist zentralistisch umsetzbar. Es braucht ein Security-by-Design schon in der Anwendungsentwicklung.
Was wäre wenn?
Erkenntnis 6: Intrusion Detection aktiv ausprobieren!
Wie groß muss ein Zeitfenster sein, bevor jemand hindurchsteigt? Hätten wir es zuverlässig bemerkt? Das sind schwierige Fragen und es gibt hier keine endgültigen Sicherheiten. Neben den erwähnten Sicherheitsmaßnahmen können Intrusion-Detection-Systeme einen Beitrag leisten.
Wenige Tage nach Bekanntwerden der Log4Shell-Lücke hat mir ein weiteres Ereignis ein sicheres Gefühl gegeben. Wir haben selbst aus dem internen Netz nach Lücken gescannt – also letztlich einen kompromittierten Rechner simuliert – und das ist sehr zügig aufgefallen.
Langer Atem und kurze Wege
Erkenntnis 7: Auch für weitere Java-Anwendungen, die nicht auf Spring basieren, waren wir schnell aussagefähig. Auch diese Aussagefähigkeit ist ein Wert, den es neu zu schärfen und zu schätzen gilt.
Warum hat das gut funktioniert? Neben der Kenntnis der relevanten Systeme und den entsprechenden Incident-Prozessen... Ein so hohes Maß an Komponenten-Homogenität wie wir gern möchten, ist für die viadee nicht umsetzbar: Wir müssen die Wünsche und Rahmenbedingungen von Kunden berücksichtigen und das überstimmt im Zweifel den Wunsch nach homogenen Komponenten und macht es uns oft unmöglich gemeinsame Ressourcen wie eine Parent-POM zu nutzen (und Kunden-übergreifend zu versionieren).
Wir profitieren sehr davon, dass wir als viadee Community vor einem Problem oder einer drohenden Verantwortung nicht zurückschrecken, sondern Verantwortung annehmen und gemeinsam Lösungen finden. Das ist ein zentrales viadee Kulturgut. Es hat die Aussagefähigkeit in einigen Fällen sehr begünstigt bzw. ermöglicht.
Interessant für mich ist auch, dass wir für unsere selbst entwickelten Systeme deutlich früher belastbar aussagefähig (bzw. schon mit Patches fertig) waren, als bei den eher monolithischen Standardsoftware-Komponenten, die wir selbst einsetzen. Die Haftungsfrage ist dort eindeutig. Dennoch sind wir dort operativ auf die Reaktions- und Kommunikationszeiten der Standardsoftware-Anbieter:innen angewiesen, was sich nicht gut anfühlt.
Darüber hinaus: Es gilt nicht nur unsere eigenen Hausaufgaben zu machen, sondern auch unseren Kunden beizustehen. Ein wichtiger Erfolgsfaktor dafür ist, dass die Menschen, die vor vielleicht 10 Jahren eine Anwendung konzipiert und an einen Kunden übergeben haben noch viadee Mitarbeiter:innen sind. Sie identifizieren sich auch oft noch mit ihren alten Projektergebnissen und erinnern sich an Dependencies von Projekten, auf deren Code sie schon keinen Zugriff mehr haben. Danke dafür!
zurück zur Blogübersicht