Skip to main content

PHP-Container absichern

Artikel von
Headshot of Neema Muganga

Neema Muganga

feature safe containers

4. August 2022

0 Min. Lesezeit

Laut Wappalyzer läuft PHP auf über zwölf Millionen Websites. Nicht schlecht für eine 28 Jahre alte Sprache! Trotz ihres Alters hat PHP mit modernen Entwicklungspraktiken Schritt gehalten. Dank der Unterstützung für Typdeklarationen und hervorragender Frameworks wie Laravel und Symfony eignet sich PHP nach wie vor hervorragend für die Entwicklung von Web-Apps. 

PHP eignet sich gut für Container-Umgebungen. Da auf Docker Hub ein offizielles Image verfügbar ist, können Entwickler auf bewährte PHP-Container-Images zugreifen, auf denen sie aufbauen können.

Dennoch ist beim Erstellen von Container-Images für PHP-Anwendungen Vorsicht geboten. Da PHP allgegenwärtig und weit verbreitet ist, sind PHP-Anwendungen ein großes und attraktives Ziel für Angreifer. Außerdem verwenden wir bei der Arbeit mit Containern und Microservices wahrscheinlich PHP-Container zusammen mit Anwendungen von Drittanbietern. Dadurch entsteht ein weiterer Angriffsweg für Schwachstellen.

Allzu oft gehen Entwickler davon aus, dass Container-Isolation Container grundsätzlich sicher macht. Diese falsche Annahme führt zu Nachlässigkeit. Ein wachsames Auge auf die Sicherheit bleibt unerlässlich. Mit etwas Sorgfalt und Vorsicht ist es jedoch nicht schwer, sichere containerisierte PHP-Apps zu entwickeln und auszuführen.

Sehen wir uns also einige Best Practices zum Absichern von PHP-Containern in der Praxis an.

Voraussetzungen

Wenn Sie diese Best Practices selbst umsetzen und der Demonstration folgen möchten, benötigen Sie die folgenden Tools:

  • Docker ist auf Ihrem Rechner installiert. Wir verwenden Docker, um unsere PHP-Container auszuführen und die integrierten Funktionen von Docker zu nutzen, um sie abzusichern.

  • Ein kostenloses Snyk-Konto. Mit den Sicherheitsscans von Snyk machen wir Schwachstellen in unseren Containern sichtbar und beheben sie.

  • Node.js, um die Snyk CLI zu installieren und auszuführen, oder konsultieren Sie die Dokumentation zur Installation der Snyk CLI mit verschiedenen anderen Methoden.

Bewährte Container-Praktiken, die Sie beachten sollten

Container sind eine praktische Möglichkeit, PHP-Apps auszuführen. Container-Runtimes wie Docker isolieren Container zwar voneinander und vom Host-Betriebssystem, doch diese Isolation ist nicht perfekt und wurde bereits umgangen.

Es gibt jedoch verschiedene Maßnahmen, mit denen Sie Ihre PHP-Container sicherer machen können:

Ressourcen begrenzen und Kontingente verwenden

Wenn Sie Ressourcen-Kontingente für einzelne Container konfigurieren, begrenzen Sie die Anzahl der Systemressourcen, die ein Container nutzen kann. Dazu zählen der Speicher und die CPU, die der Container beansprucht, sowie die Festplatten-E/A-Bandbreite. PHP-Entwickler können mehrere Optionen der Container-Runtime nutzen, um den Ressourcenzugriff eines Containers zu begrenzen.

CPUs

Mit dem Flag –-cpus <value> legen Sie die Anzahl der CPUs fest, die der Container nutzen kann. Wenn wir beispielsweise --cpus 3.5 festlegen, kann der Container genau dreieinhalb der verfügbaren CPUs oder CPU-Kerne nutzen.

Wenn Sie eine feinere Kontrolle benötigen, lesen Sie in der Docker-Dokumentation mehr über die Flags cpu-quota und cpu-period. Beachten Sie jedoch, dass Sie die Perioden des Linux-Schedulers verstehen müssen, um die Flags effektiv einzusetzen.

So führen Sie einen PHP-Container mit CPU-Nutzungsbeschränkungen aus:

$ docker run -it --cpus 3.5 php:7.4-cli /bin/bash

Speicher

Mit dem Flag -m oder –memory= legen Sie den maximal verfügbaren Speicher für den Container fest. Sie können eine positive Ganzzahl verwenden, gefolgt von b, k, m oder g, um Byte, Kilobyte, Megabyte beziehungsweise Gigabyte anzugeben.

Mit dem folgenden Befehl begrenzen wir beispielsweise die Speicherreservierung unseres Containers auf 800 MB und legen den maximalen RAM auf 1,5 GB fest.

$ docker run -it --memory 1.5g --memory-reservation 800m php:7.4-cli /bin/bash

Wenn Sie die für einen Container verfügbaren Ressourcen begrenzen, verringern Sie die möglichen Auswirkungen eines Angriffs. Denn so sinkt die Wahrscheinlichkeit, dass ein Container so viele Ressourcen verbraucht, dass der Betrieb des Host-Betriebssystems oder anderer Container beeinträchtigt wird. Dieser Ansatz erhöht die Sicherheit jedes einzelnen Containers und verbessert die Gesamtsicherheit der Host-Umgebung.

Container ohne Kontingente machen ein System anfällig für Denial-of-Service-Angriffe (DoS). Ein DoS-Angriff kann die laufenden Dienste eines Systems lahmlegen und dadurch die Servicequalität für Nutzer beeinträchtigen. Das zeigt, dass Container ohne Kontingente zu einem Sicherheitsrisiko für das Unternehmen werden können, wenn sie nicht richtig verwaltet werden.

Wenn Sie PHP-Container mit Kubernetes statt Docker ausführen, ist es für die Sicherheit der Container entscheidend, die Kontexteinstellungen von Kubernetes zu verstehen.

Container nicht als Root ausführen

Am besten führen Sie Container nicht als Root-Benutzer und auch nicht mit einem Benutzerkonto aus, das über mehr Berechtigungen als nötig verfügt. Befolgen Sie stattdessen beim Erstellen von Benutzerkonten für Ihre Container stets das Prinzip der geringsten Berechtigungen.

Die meisten Container-Runtimes bieten Möglichkeiten, Container mit einem Nicht-Root-Benutzerkonto auszuführen. Docker stellt einen Rootless-Modus bereit, in dem die Container-Runtime und alle Container mit einem regulären Benutzerkonto ausgeführt werden.

Auch Kubernetes bietet verschiedene Optionen, um Nodes und Container ohne Root-Rechte auszuführen. Allgemeiner gesagt: Mit jeder OCI-konformen Container-Runtime können Sie über die UID- und GID-Eigenschaften in Ihrer Runtime-Konfigurationsdatei genau festlegen, welcher Benutzer und welche Gruppe verwendet werden sollen.

Wenn Sie Snyk verwenden, um Ihre Kubernetes-Konfigurationsdateien oder Terraform-IaC-Dateien zu scannen, profitieren Sie davon, dass die oben genannten Fehlkonfigurationen erkannt werden, zum Beispiel Speicherlimits nicht festgelegt oder Container wird als Root ausgeführt. Snyk hebt diese visuell hervor und verweist auf die betreffenden Codezeilen in der YAML-Datei, die diese Best Practices für die Sicherheit nicht erfüllen:

Eine Sicherheitsanalyse weist auf Probleme mit Kubernetes-Containern hin. Eine Deployment-YAML-Datei hebt die gemeinsame Nutzung der Host-PID, fehlende Speicherlimits und privilegierte Einstellungen hervor.

Am Beispiel von Docker: PHP-Container im Rootless-Modus auszuführen, unterscheidet sich kaum davon, wenn Docker als Root läuft. Alle üblichen Docker-Befehle sollten funktionieren. Beachten Sie jedoch, dass die Berechtigungen, die Sie einem Container gewähren können, auf die Berechtigungen des Benutzerkontos beschränkt sind, unter dem der Docker-Daemon läuft. Es gibt einen Haken: Wenn Sie den Docker-Daemon bereits mit seiner Standardkonfiguration installiert haben, müssen Sie ihn deinstallieren und im Rootless-Modus neu installieren. Folgen Sie dazu den Anweisungen in der Docker-Dokumentation.

In Containern keine Root-Benutzer verwenden

Zusätzlich zum Ausführen von Containern im Rootless-Modus sollten wir vermeiden, innerhalb unserer Container einen Root-Benutzer zu verwenden. Das mag überflüssig erscheinen, wenn der Container bereits im Rootless-Modus läuft, bietet aber eine zusätzliche Schutzebene vor böswilligen Nutzern.

Wir können unseren PHP-Container als Nicht-Root-Benutzer ausführen, indem wir die Direktive USER in der Dockerfile verwenden. So läuft der Container im Kontext eines Benutzers oder einer Gruppe mit möglichst wenigen Berechtigungen.

Wenn ein Docker-Basis-Image keinen Benutzer mit geringen Berechtigungen enthält, können wir während des Image-Builds einen Nicht-Root-Benutzer hinzufügen. Dieser steht dann beim Erstellen eines neuen Container-Images zur Verfügung, wie die folgende Dockerfile zeigt:

FROM php:7.4-cli
# the command below adds a new user or a group with a userid 1002
RUN groupadd -g 1002 appuser && \
    useradd -r -u 1002 -g appuser appuser
# command below changes a default root user to one with non-root privileges
USER appuser
CMD ["touch", "/root/example.txt"]

Offizielle PHP-Container-Images enthalten ein nicht privilegiertes Benutzerkonto namens nobody. Wenn Sie also ein Container-Image auf Basis eines der offiziellen Docker-Basis-Images erstellen, können Sie diesen Benutzer verwenden, statt selbst einen anzulegen (wie oben gezeigt):

FROM php:7.4-cli
USER nobody
CMD ["touch", "/root/example.txt"]

Wenn wir das Docker-Image nun im interaktiven Modus ausführen und versuchen, die in der Dockerfile für den Root-Benutzer erstellte Textdatei anzuzeigen, sehen wir, dass wir keinen Zugriff darauf haben:

$ cat /root/example.txt
cat: /root/example.txt: Permission denied

Die wichtigste Erkenntnis: Wenn Root sowohl auf Runtime-Ebene als auch innerhalb von Containern vermieden wird, müsste ein bösartiges Docker-Anwendungs-Image oder eine kompromittierte Container-Anwendung zwei erfolgreiche Rechteausweitungen durchführen, um in das Host-Betriebssystem einzudringen, auf dem der Container läuft, und von dort aus die laterale Bewegung fortzusetzen.

Rootless-Container lassen sich jedoch nicht immer einsetzen. Manchmal benötigen containerisierte Anwendungen Zugriff auf Hardware wie eine GPU. Glücklicherweise können wir zusätzliche Schutzebenen einrichten.

Schwachstellen in Containern mit automatisierten Tools beheben

In Containern verbergen sich zahlreiche potenzielle Schwachstellen. Bibliotheken und Anwendungen im Basis-Image sowie zusätzlich installierte Pakete können CVEs oder andere Schwachstellen enthalten. Wie würden Sie davon erfahren? Die meisten Entwicklungs- und DevOps-Teams haben keine Zeit, den Sicherheitsverlauf jedes in ihren Containern installierten Pakets manuell zu verfolgen. 

Zum Glück können automatisierte Container-Scans helfen. Snyk Container ist kostenlos und scannt unsere Images automatisch. Außerdem benachrichtigt es uns sofort über Schwachstellen in Paketen und Open-Source-Bibliotheken innerhalb unserer Container. So können wir Fehlerbehebungen ausrollen, sobald eine Schwachstelle auftritt, bevor Angreifer sie ausnutzen können. Snyk schlägt außerdem automatisch Korrekturen vor, indem Pull Requests mit aktualisierten Basis-Images und empfohlenen Image-Tags erstellt werden.

Mit Snyk lassen sich Container schnell und einfach auf Schwachstellen scannen. Wenn Node.js und npm installiert sind, müssen wir nur npm install snyk@latest -g ausführen, um die Snyk CLI zu installieren.

Führen Sie anschließend Folgendes aus:

snyk auth

Dieser Befehl öffnet in unserem Browser eine Authentifizierungsseite:

Snyk-Webseite, auf der Nutzer aufgefordert werden, ihr Gerät für die Snyk CLI zu authentifizieren. Die Schaltfläche trägt die Aufschrift „Authenticate“.

"blog-php-container-authenticateWenn wir auf die Schaltfläche Authenticate klicken, wird in unserem Terminal eine Meldung angezeigt, die die erfolgreiche Authentifizierung bestätigt.

Nun können wir die Snyk CLI verwenden, um unsere Container mit folgendem Befehl zu scannen:

snyk container test <your-image>

Beim Scan eines PHP-7.4-Basis-Images erhalten wir folgendes Ergebnis:

Terminal-Scan des Basis-Images php:7.4.30-cli-bullseye meldet 87 Schwachstellen: 2 kritisch, 4 hoch, 2 mittel und 79 niedrig.
Der Snyk-Container-Scan hat 87 Probleme im Basis-Image gefunden.

Idealerweise führen wir einen Container-Scan in unserer CI/CD-Pipeline aus, damit wir niemals einen anfälligen Container in der Produktion bereitstellen. Mit dem Befehl „container monitor“ können wir außerdem die Testergebnisse unseres Container-Images an Snyk senden. So kann Snyk die Informationen in unserem Dashboard anzeigen und uns über potenzielle zukünftige Schwachstellen in unserem Image benachrichtigen.

snyk container monitor <your-image>

Beim Scan desselben PHP-Images, das wir gerade getestet haben, erhalten wir folgendes Ergebnis:

Docker-Imageübersicht mit dem PHP-7.4-CLI-Image, Debian 11 als Zielbetriebssystem und Empfehlungen für ein Upgrade des Basis-Images

War das nicht einfach? Und wir sind noch nicht fertig. Mit Snyk Code können wir auch sicherstellen, dass unser PHP-Code sicher ist, bevor wir ihn containerisieren.

Wechseln Sie zu dem Ordner, in dem sich die Manifestdatei Ihrer PHP-Anwendung befindet, und führen Sie den folgenden Befehl aus, um die Ausgabe anzuzeigen:

snyk code test

Wir können einen Snyk-Code-Test für ein älteres Laravel-Projekt ausführen, um ein häufiges Szenario zu prüfen: Schwachstellen in einem veralteten, aber noch funktionierenden PHP-Projekt finden. Das Ergebnis sehen Sie hier:

Terminalausgabe mit schwerwiegenden Sicherheitslücken im Laravel-Framework, darunter SQL-Injection, unzureichende Eingabevalidierung und Remote Code Execution.

Wie bei der Container-Überwachung können wir Snyk auch unseren Code überwachen lassen, indem wir im Hauptverzeichnis unserer PHP-App snyk monitor ausführen. Anschließend erscheint die Anwendung in unserem Snyk-Dashboard.

Snyk-Projekt-Dashboard mit neu veröffentlichten Schwachstellen in der Datei composer.lock des Laravel-Projekts.

Sicherheitsscans auf Container- und Code-Ebene bieten eine hervorragende Möglichkeit, sicherzustellen, dass wir sichere Container und sicheren Code bereitstellen.

Vertrauenswürdige Container-Images verwenden

Eine Möglichkeit, unsere PHP-Container abzusichern, besteht darin, Images aus sicheren und vertrauenswürdigen Online-Registries zu beziehen. In solchen Registries finden sich seltener Images mit veraltetem oder bösartigem Code, der unsere Container-Umgebung einem Datenleck aussetzen könnte. Docker Hub enthält beispielsweise eine Vielzahl vertrauenswürdiger Images, die Docker gründlich auf Schwachstellen überprüft. Auch die Anbieter werden von Docker verifiziert, bevor Nutzer auf die Images zugreifen können.

Allerdings sind nicht alle Images auf Docker Hub vertrauenswürdig. Wenn wir Online-Registries verwenden, sollten wir den Inhalt der Images auf potenzielle Sicherheitslücken überprüfen. Wir können ein Image vor dem Herunterladen auf das Host-System auf bösartigen Code scannen, der den Container gefährdet. Damit dieser Schritt nicht vergessen wird, können wir ein Sicherheitstool wie Snyk direkt in unsere Entwicklungstools oder Workflows integrieren, um potenzielle Sicherheitslücken in unseren Containern zu überwachen und zu beheben.

Über das Scannen hinaus können wir sicherstellen, dass wir vertrauenswürdige Container-Images verwenden, indem wir Docker Hub, das Programm Docker Verified Publisher und Docker Official Images nutzen. Das Programm Docker Verified Publisher überprüft, ob Images, die von dort abgerufen werden, aus vertrauenswürdigen Quellen stammen. So wird sichergestellt, dass Nutzer keine unsicheren Images aus gefälschten Repositories beziehen.

Alternativ können wir von Docker Content Trust verifizierte Images verwenden. Docker 1.8 führte Docker Content Trust ein, um die digitale Signatur von Images und die Image-Authentifizierung zu stärken. Das Signieren von Images überprüft die Quelle eines Container-Images und stellt sicher, dass das Image nicht manipuliert wurde. Außerdem legt es die Richtlinien fest, anhand derer validierte Images bestimmt werden, die Nutzer auf ihre Systeme laden.

Auch wenn Sie offizielle Docker-Images von verifizierten Docker-Publishern oder über Docker Content Trust beziehen, um Ihre Container-Umgebung zu schützen, ist es wichtig, Snyk zum Schutz unserer Container einzusetzen.

PHP-Entwickler tragen Verantwortung für die Sicherheit ihrer Container

Um PHP-Container vor potenziellen Sicherheitsbedrohungen zu schützen, müssen während des gesamten Anwendungslebenszyklus verschiedene Sicherheitstechniken eingesetzt werden – vom Build über die Bereitstellung bis zur Laufzeit. Zusätzlich zu den Best Practices für die Container-Sicherheit von PHP-Anwendungen können wir mit Snyk die Sicherheit unserer Container mithilfe automatisierter Tools gewährleisten, zum Beispiel durch:

  • Automatisierte Sicherheitstests in CI/CD-Pipelines, etwa durch Integrationen mit GitHub Actions oder AWS Code Pipeline

  • Kombinierte Sicherheitsinformationen zu Containern und Quellcode

  • Kubernetes-Integration zur Überwachung von Containern in unseren Kubernetes-Clustern auf neue und bereits vorhandene Schwachstellen

  • Ein entwicklerorientierter Ansatz, der Sicherheitsprobleme in Ihrem eigenen PHP-Code erkennt und es Entwicklern erleichtert, Probleme zu beheben – auch ohne umfassende Sicherheitserfahrung

Snyk Container ist ein Tool für das Management von Container-Schwachstellen, das uns dabei hilft, Sicherheitsrisiken in Containern umfassend und effizient zu erkennen und zu beheben. Mit integrierten IDE-Prüfungen, automatisierter CI/CD-Integration, nativem Git-Scanning und Testfunktionen für Produktionsumgebungen schützt Snyk Container unsere Kubernetes-Container und -Workloads über den gesamten Softwareentwicklungslebenszyklus hinweg.

Container-Sicherheit mit Fokus auf Entwickler

Snyk findet und behebt automatisch Schwachstellen in Container-Images und Kubernetes-Workloads.

Darüber hinaus kann Snyk Schwachstellen erkennen, indem Sicherheitsscans in Entwicklungstools wie VS-Code und JetBrains integriert werden. So erhalten Sie während der Entwicklung von Anwendungen weitere Informationen zu den Arten von Schwachstellen und vorgeschlagenen Korrekturen.

Snyk unterstützt Entwickler auch dabei, Schwachstellen zu erkennen, die die Container-Sicherheit gefährden. Diese Probleme werden automatisch behoben. Das steigert die Produktivität und hilft Entwicklungsteams, weniger Zeit mit der Behebung von Codeproblemen und mehr Zeit mit der Entwicklung von Anwendungen zu verbringen. Erstellen Sie noch heute Ihr kostenloses Konto. Mit unserem kostenlosen Online-Tool PHP-Code-Prüfer können Sie außerdem sehen, wie die Snyk-Code-Engine Ihren Code auf Sicherheits- und Qualitätsprobleme analysiert.