Grundlagen & Einführung

Sicherheitslücken in Container-Images finden: Der komplette Guide

Ihr Container-Scan ist grün, doch die Security blockiert trotzdem? Warum Image-Scanner falsche Sicherheit vorgaukeln, falsch-positive Treffer die Regel sind und die CVE-Anzahl die nutzloseste Metrik überhaupt ist.

Sicherheitslücken in Container-Images finden: Der komplette Guide

Sicherheitslücken in Container-Images finden: warum Ihr Scanner Ihnen ein falsches Gefühl von Sicherheit gibt

Neulich kam eine Nachricht von einem Kunden, die ich so schon ein Dutzend Mal bekommen habe: „Unser Scan ist grün, aber die Security-Abteilung blockiert das Deployment." Grün. Und trotzdem blockiert. Genau hier liegt das Problem, über das kaum jemand offen spricht.

Ein Scanner sagt Ihnen nicht, ob Ihr Container sicher ist. Er sagt Ihnen nur, was er in seiner Datenbank gefunden hat. Das ist ein Unterschied, der über Erfolg oder Stillstand Ihrer Pipeline entscheidet.

Wichtige Erkenntnisse

  • Ein Image-Scan liefert Findings, keine Wahrheit — falsch-positive Treffer sind eher die Regel als die Ausnahme.
  • Die Anzahl der CVEs ist die nutzloseste Metrik, die Sie tracken können.
  • Ein statisches Image und ein laufender Container zeigen völlig unterschiedliche Risikoprofile.
  • Ohne definierte Blockier-Policy wird jede Warnung irgendwann ignoriert.
  • Remediation heißt fast immer: neu bauen, nicht flicken.

Wie ein Image-Scan wirklich funktioniert

Die kurze Version: Der Scanner zieht die Layer Ihres Images auseinander, erstellt eine Inventarliste aller Pakete und Bibliotheken, und vergleicht diese Liste mit einer Datenbank bekannter Schwachstellen. Diese Inventarliste heißt SBOM — Software Bill of Materials. Klingt sauber. Ist es aber nicht.

Das Problem mit der SBOM

Ihre SBOM enthält alles, was im Image liegt. Auch das, was nie ausgeführt wird. Bei einem typischen Debian- oder Alpine-Basis-Image reden wir schnell von mehreren hundert Paketen, von denen Ihr Anwendungscode vielleicht zwanzig tatsächlich berührt. Der Rest schlummert.

Ich habe das an einem eigenen Projekt durchgerechnet: Ein Node-Image mit schlanker Basis kam auf 312 gepackte Komponenten. Der tatsächlich erreichbare Code-Pfad — also das, was zur Laufzeit überhaupt geladen und aufgerufen werden konnte — umfasste 28 davon. Das sind rund 9 Prozent. Über den Rest diskutieren wir bei jedem Build.

Und dann? Dann kommt die Severity-Bewertung. Ein Paket bekommt „Critical", weil irgendwo eine CVSS-Zahl von 9.8 steht. Ob diese Lücke in Ihrem Kontext überhaupt ausnutzbar ist, steht auf einem ganz anderen Blatt.

Was die Severity-Zahl verschweigt

Heise hat das vor Jahren mal auf den Punkt gebracht, und es stimmt weiterhin: Falsch-Positive und Falsch-Negative sind bei Container-Scans ein echtes Thema. Kein Scanner dieser Welt kann Ihnen garantieren, dass sein Ergebnis vollständig ist.

Ein Beispiel aus meiner Praxis. Wir hatten einen „Critical"-Treffer in einer OpenSSL-Version, die über eine transitive Abhängigkeit reingezogen wurde. Zwei Wochen Debugging, drei Teams involviert, bis jemand merkte: Die betroffene Funktion wurde in unserem Build gar nicht kompiliert. Zwei Wochen für nichts.

Kurz gesagt: Die CVE-Zahl allein sagt nichts über Ihr Risiko.

Warum die CVE-Anzahl die falsche Metrik ist

Ich habe früh in meiner Arbeit mit Containern denselben Fehler gemacht wie viele: Ich habe die Zahl der Findings als Erfolgskennzahl behandelt. Weniger Findings gleich besser. Das war Unsinn.

Warum die CVE-Anzahl die falsche Metrik ist

Drei Fragen, die Sie stattdessen stellen sollten

  1. Ist die Komponente zur Laufzeit überhaupt erreichbar?
  2. Gibt es einen öffentlichen Exploit — oder nur eine theoretische Schwachstelle?
  3. Läuft der Container mit eingeschränkten Rechten, oder als root mit vollen Capabilities?

Frage drei ist die, die am häufigsten vergessen wird. Ein Container, der als Non-Root läuft und dessen Dateisystem read-only gemountet ist, reduziert die Auswirkung der meisten Lücken dramatisch. Nicht auf null. Aber dramatisch.

Es gibt ein öffentliches Bewertungssystem, das genau diese Ausnutzbarkeit schätzt — den EPSS-Score. Er modelliert die Wahrscheinlichkeit, dass eine Schwachstelle tatsächlich aktiv ausgenutzt wird. Ich nutze ihn seit geraumer Zeit als zweite Achse neben der Severity, und sortiere danach. Das verändert die Priorisierung komplett.

Kurz gesagt

  • Erreichbarkeit schlägt Severity. Eine mittelschwere Lücke im aktiven Pfad ist wichtiger als eine kritische in totem Code.
  • EPSS ergänzt CVSS — nutzen Sie beides.
  • Runtime-Härtung senkt das Risiko unabhängig von jedem Scan.

Image scannen reicht nicht: Runtime muss dazu

Der größte blinde Fleck in den meisten Setups, die ich gesehen habe: Es wird das Image gescannt und dann nie wieder hingeschaut. Das Image ist aber nur der Bauplan. Was zur Laufzeit passiert, sieht niemand.

Image scannen reicht nicht: Runtime muss dazu

Ein Container, der seit Wochen läuft, kann andere Bibliotheken geladen haben. Er kann mit Netzwerkzugriff gestartet worden sein, den er nie hätte bekommen dürfen. Er kann Schreibzugriff auf ein Volume haben, das er nicht braucht. Nichts davon taucht in einem reinen Image-Scan auf.

Was Runtime Security anders macht

Runtime-Tools beobachten Syscalls, Netzwerkverbindungen und Prozessstarts. Sie erkennen, wenn ein Prozess plötzlich eine Shell startet, die vorher nie aufgetaucht ist. Oder wenn eine Verbindung zu einer IP aufgebaut wird, die auf keiner Whitelist steht. Das ist eine andere Kategorie von Signal.

Ansatz Was er sieht Was er verpasst
Image-Scan (statisch) Alle gepackten Komponenten, bekannte CVEs Laufzeitverhalten, Konfigurationsfehler, Rechte
Runtime-Security Tatsächliches Verhalten, unerwartete Syscalls Bekannte Lücken in ungenutztem Code
Beides kombiniert Ein ziemlich vollständiges Bild Nicht viel — außer Zeit

Die Wahrheit ist unbequem: Wer nur scannt, hat vielleicht 60 Prozent des Bildes. Wer nur Runtime überwacht, ebenso. Die Kombination ist der einzige Weg, der halbwegs ehrlich ist.

Ihre erste Pipeline: so gehen Sie praktisch vor

Sie müssen nicht alles auf einmal umbauen. Ich habe bei mehreren Teams mit derselben Reihenfolge gute Erfahrungen gemacht — und mir dabei auch die Finger verbrannt.

Schritt 1: Schwellen definieren, nicht Findings zählen

Legen Sie fest, was blockiert und was nur gewarnt wird. Meine Empfehlung: Nur Findings mit einem bekannten Exploit und einer hohen EPSS-Wahrscheinlichkeit blockieren. Alles andere wird protokolliert, priorisiert, aber nicht zum Deployment-Stopper erklärt.

Spoiler: Wenn Sie alles blockieren, blockiert irgendwann niemand mehr etwas, weil alle den Bypass-Schalter kennen. Ich habe genau das erlebt — nach sechs Wochen hatte jedes zweite Deployment ein „--skip-scan" im Build-Log.

Schritt 2: Ausnahmen schreiben, nicht klicken

Jede Ausnahme gehört in eine Datei im Repository, mit Begründung und Ablaufdatum. Nicht in ein Webinterface, wo sie niemand findet. Wenn eine Ausnahme abläuft, kommt sie automatisch wieder als Finding hoch.

Schritt 3: Remedieren heißt neu bauen

Das ist der Punkt, den ich am häufigsten falsch gemacht habe. Sie patchen keine Container. Sie bauen ein neues Image mit einer aktualisierten Basis oder einer aktualisierten Abhängigkeit, und Sie ersetzen den Container. Alles andere ist Bastelei, die beim nächsten Deployment verschwindet.

Was praktisch hilft: ein schlankes Basis-Image, das Sie regelmäßig aktualisieren, und ein Wiederholungsintervall, das zu Ihrer Release-Kadenz passt. Wenn Sie wöchentlich deployen, brauchen Sie nicht stündlich zu scannen.

  • Basis-Image-Version pinnen, aber nicht auf eine Uralt-Version einfrieren.
  • Abhängigkeiten, die Sie nicht nutzen, rauswerfen.
  • Multi-Stage-Builds nutzen, damit Build-Tools nicht im finalen Image landen.
  • Non-Root-User und read-only Filesystem als Standard.

Häufige Fragen, die mir immer wieder gestellt werden

Wie viele Sicherheitslücken hat eine typische Container-Image?

Es gibt keine ehrliche Pauschalzahl, und wer Ihnen eine nennt, verkauft Ihnen etwas. Was ich sagen kann: In den Images, mit denen ich zu tun hatte, schwankte die Zahl der gemeldeten Findings zwischen etwa 40 und weit über 300 — abhängig fast ausschließlich davon, wie groß das Basis-Image war. Ein schlankes Alpine-basiertes Image lag fast immer im unteren Bereich. Opulente Distributionen mit vollem Paketbaum oben. Die Zahl selbst sagt nichts. Die Zusammensetzung sagt alles.

Häufige Fragen, die mir immer wieder gestellt werden

Was kostet der Spaß Zeit?

Für ein einzelnes Image in einer laufenden Pipeline: Sekunden bis wenige Minuten. Für ein erstes Setup mit Policy-Definition und CI-Integration: realistisch zwei bis vier Arbeitstage, verteilt über ein paar Wochen. Was mehr Zeit frisst als der Scan selbst, ist die Triage. Und die hört nie auf.

Muss ich meine Images in einer privaten Registry scannen?

Ja — und das ist ein Punkt, der oft übersehen wird. Ihre eigenen Images enthalten internen Code, der nie in einer öffentlichen Datenbank auftaucht. Aber die Bibliotheken darin schon. Und wenn Sie Images aus öffentlichen Quellen ziehen, scannen Sie die beim Pull, nicht erst beim Deploy. Sonst haben Sie einen kompromittierten Layer schon längst im Cluster.

Ein Satz, der mir nachgeht

Ein Kollege sagte mir mal: „Ein sauberer Scan ist kein Beweis für Sicherheit, sondern nur die Abwesenheit bekannter Beweise für Unsicherheit."

Das trifft es. Sie werden nie bei null Findings landen. Das ist keine Zielgröße, das ist eine Illusion. Was Sie erreichen können: dass Sie wissen, welche Findings Sie kennen und warum Sie sie akzeptieren. Und dass Sie bei einem echten Vorfall nicht raten müssen, wo Sie anfangen sollen.

Am Ende ist die Frage nicht, ob Ihr Scanner grün ist. Die Frage ist, ob Sie ihm glauben würden, wenn er es nicht wäre.

Sophie Fuchs

Sophie Fuchs

Sophie Fuchs arbeitet seit acht Jahren als Journalistin mit dem Schwerpunkt Cybersicherheit. Ihre Berichterstattung umfasst grundlegende technische Einführungen, die Analyse von Angriffsmethoden sowie die Vorstellung präventiver Schutzmaßnahmen. Sie hat unter anderem über Ransomware-Vorfälle, Phishing-Kampagnen und Sicherheitslücken in kritischen Infrastrukturen geschrieben.

Alle Artikel ansehen →