Weniger Angriffsfläche, mehr Kontrolle
Ein Magento-Produktivserver ist nur so sicher wie sein am wenigsten gehärteter Dienst. Dieser Artikel zeigt praxisnah, wie sich die Angriffsfläche durch Deaktivieren unnötiger Dienste, automatische Sicherheitsupdates, konsequente Non-Root-Ausführung, korrekte Dateisystemrechte, fail2ban und SSH-Härtung systematisch reduzieren lässt, mit direktem Bezug zum Mark-Shust-Docker-Setup und typischen Debian- oder Ubuntu-Produktivumgebungen.
Inhaltsverzeichnis
- 1. Minimale Angriffsfläche: Dienste, Ports und Pakete reduzieren
- 2. Automatische Sicherheitsupdates: unattended-upgrades und dnf-automatic
- 3. Anwendungsprozesse ohne Root-Rechte betreiben
- 4. Dateisystem-Berechtigungen für den Magento-Webroot auditieren
- 5. Intrusion Prevention mit fail2ban gegen Brute-Force-Angriffe
- 6. SSH-Härtung: Key-Only-Auth, kein Root-Login, alternativer Port
- 7. Firewall-Grundlagen mit ufw als letzte Verteidigungslinie
- 8. Praktische Hardening-Checkliste für den Magento-Produktivserver
- 9. Server-Hardening im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Minimale Angriffsfläche: Dienste, Ports und Pakete reduzieren
Das Prinzip der minimalen Angriffsfläche ist denkbar einfach: Jeder laufende Dienst, jeder offene Port und jedes installierte Paket ist ein potenzieller Angriffsvektor, unabhängig davon, ob er aktuell genutzt wird. Ein frisch aufgesetztes Debian- oder Ubuntu-Server-Image bringt standardmäßig Dienste wie avahi-daemon, cups, rpcbind oder einen vollständigen Mail-Transport-Agent mit, die auf einem reinen Magento-Produktivserver niemals gebraucht werden. Jeder dieser Dienste läuft mit eigenen Rechten, öffnet unter Umständen einen Netzwerk-Port und muss unabhängig vom Kern-Stack gepatcht werden, was die Wartungslast erhöht, ohne einen funktionalen Mehrwert zu liefern.
Der praktische Einstieg ist eine Bestandsaufnahme: systemctl list-unit-files --state=enabled zeigt alle aktiv gestarteten Dienste, ss -tulpn listet alle tatsächlich lauschenden Sockets inklusive des zugehörigen Prozesses. Ein Magento-Produktivserver braucht in der Regel nur nginx, php-fpm, eine Datenbankverbindung, gegebenenfalls Redis und OpenSearch lokal oder als separate Hosts sowie SSH für die Administration. Alles andere sollte deaktiviert, maskiert und wo möglich vollständig deinstalliert werden, denn ein maskierter Dienst kann nicht versehentlich durch ein Paket-Update reaktiviert werden.
#!/usr/bin/env bash
# harden-attack-surface.sh - disable unused services and audit listening ports
set -euo pipefail
echo "[INFO] Currently enabled services"
systemctl list-unit-files --state=enabled
# Disable and mask services not required on a Magento production host
for svc in avahi-daemon cups rpcbind bluetooth ModemManager; do
if systemctl list-unit-files | grep -q "^${svc}.service"; then
systemctl disable --now "${svc}.service"
systemctl mask "${svc}.service"
echo "[OK] Disabled and masked ${svc}"
fi
done
echo "[INFO] Listening TCP/UDP sockets and owning processes"
ss -tulpn
# Remove packages that are no longer required after disabling services
apt-get purge -y avahi-daemon cups-common rpcbind || true
apt-get autoremove -y --purge
2. Automatische Sicherheitsupdates: unattended-upgrades und dnf-automatic
Automatische Sicherheitsupdates schließen das Zeitfenster zwischen der Veröffentlichung eines Patches und seiner tatsächlichen Installation, das bei manueller Pflege oft Wochen oder Monate beträgt. Auf Debian- und Ubuntu-Systemen übernimmt das Paket unattended-upgrades diese Aufgabe, konfiguriert über /etc/apt/apt.conf.d/50unattended-upgrades und aktiviert über /etc/apt/apt.conf.d/20auto-upgrades. Auf RHEL-basierten Systemen wie AlmaLinux oder Rocky Linux übernimmt dnf-automatic dieselbe Rolle, gesteuert über /etc/dnf/automatic.conf mit dem systemd-Timer dnf-automatic-install.timer. Beide Werkzeuge lassen sich so konfigurieren, dass ausschließlich als sicherheitsrelevant markierte Pakete aus dem jeweiligen Security-Repository automatisch installiert werden, während reguläre Feature-Updates manuell bleiben.
Der entscheidende Zielkonflikt auf einem Produktivsystem ist die Balance zwischen Patch-Geschwindigkeit und Stabilität. Ein automatisches Update von PHP, nginx oder MySQL auf eine neue Minor-Version kann in seltenen Fällen ein Verhalten ändern, von dem Magento oder eine Extension abhängt, und genau zur Unzeit einen Ausfall verursachen. Sinnvoll ist deshalb, Unattended-Upgrade::Origins-Pattern strikt auf den Security-Origin zu begrenzen, kritische Pakete wie den Datenbankserver über eine Blacklist auszunehmen und Benachrichtigungs-Mails bei jeder automatischen Installation zu aktivieren. Ein Reboot nach Kernel-Updates sollte nie automatisch erfolgen, sondern über Unattended-Upgrade::Automatic-Reboot "false" an ein geplantes Wartungsfenster gebunden werden.
Dasselbe Prinzip gilt für dnf-automatic: Über den Parameter upgrade_type = security in /etc/dnf/automatic.conf werden ausschließlich sicherheitsrelevante Pakete berücksichtigt, während apply_updates = yes nur nach sorgfältigem Testen in einer Staging-Umgebung aktiviert werden sollte. Auf einem frisch aufgesetzten Produktivsystem empfiehlt sich zunächst ein Betrieb im reinen Benachrichtigungsmodus, um über zwei bis drei Wochen zu beobachten, welche Pakete regelmäßig betroffen wären, bevor die automatische Installation tatsächlich scharf geschaltet wird.
3. Anwendungsprozesse ohne Root-Rechte betreiben
Der Grundsatz der geringsten Rechte gilt nicht nur für Menschen, sondern genauso für Prozesse. nginx startet als root, um Port 80 und 443 zu binden, gibt diese Rechte aber sofort ab und führt die eigentlichen Worker-Prozesse unter einem unprivilegierten Benutzer wie www-data aus, konfiguriert über die Direktive user in nginx.conf. php-fpm folgt demselben Muster über die Pool-Parameter user und group in der Pool-Konfiguration unter /etc/php/8.4/fpm/pool.d/. Läuft ein php-fpm-Pool versehentlich als root, erbt jeder durch eine Schwachstelle in Magento oder einer Extension ausgeführte Code automatisch volle Systemrechte, statt auf das Nötigste beschränkt zu sein.
Im Docker-Kontext, etwa beim Mark-Shust-Setup, gilt dieselbe Regel für Container: Ein Container, dessen Hauptprozess als root läuft, macht einen Container-Escape deutlich wertvoller für einen Angreifer, weil er auf dem Host direkt mit Root-Rechten ankommt. Offizielle PHP- und nginx-Images unterstützen die user-Direktive in docker-compose.yml, um den Container-Prozess explizit auf einen unprivilegierten UID/GID-Wert zu binden. Der Deploy-User, der SSH-Zugriff auf den Produktivserver hat, sollte ebenfalls kein root sein, sondern ein dedizierter Account mit eng zugeschnittenen sudo-Rechten ausschließlich für die tatsächlich benötigten Befehle wie Cache-Flush oder Deployment-Skripte, protokolliert über sudo-Logging.
# docker-compose.yml excerpt (Mark Shust docker-magento style)
# Run the phpfpm container as a dedicated non-root user instead of the image default
services:
phpfpm:
image: markoshust/magento-php:8.4-fpm-1
user: "1000:1000" # dedicated deploy UID/GID, never 0:0
volumes:
- ./:/var/www/html:cached
environment:
- PHP_MEMORY_LIMIT=2G
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
security_opt:
- no-new-privileges:true
4. Dateisystem-Berechtigungen für den Magento-Webroot auditieren
Magento-Dateisystemrechte folgen einem einfachen Muster, das in der Praxis trotzdem häufig falsch umgesetzt wird: Der Deploy-User besitzt den gesamten Webroot, der Webserver-Prozess-User erhält nur dort Schreibrechte, wo Magento zur Laufzeit tatsächlich schreiben muss. Verzeichnisse sollten grundsätzlich 750 und Dateien 640 erhalten, sodass die eigene Benutzergruppe lesen, aber niemand außerhalb schreiben kann. Ein pauschales chmod -R 777, wie es in älteren Magento-Foren-Threads noch kursiert, öffnet jedem lokalen Prozess und im schlimmsten Fall jeder Web-Anfrage Schreibzugriff auf den gesamten Code.
Schreibrechte für den Webserver-User sind ausschließlich für var/, generated/, pub/media/ und pub/static/ nötig, weil Magento dort Cache, kompilierten Code, Produktbilder und statische Assets zur Laufzeit ablegt. Entscheidend ist, dass pub/media/ zwar beschreibbar, aber niemals ausführbar sein darf: Ein Upload-Formular, das Bilddateien nach pub/media/ schreibt, darf nicht dazu führen, dass eine dort abgelegte .php-Datei vom Webserver interpretiert wird. Das wird zusätzlich zur Dateisystemebene über eine nginx-Location-Regel erzwungen, die PHP-Ausführung in pub/media/ unabhängig von den Dateirechten blockiert.
SSH-Schlüssel unterliegen einer eigenen, strengeren Regel: ~/.ssh muss 700 haben, authorized_keys und private Schlüssel 600, sonst verweigert sshd aus gutem Grund die Anmeldung, weil zu offene Rechte bedeuten, dass andere lokale Benutzer den Schlüssel lesen oder manipulieren könnten. Ein regelmäßiges automatisiertes Audit dieser Berechtigungen deckt Drift auf, der sich über Monate durch manuelle Eingriffe unbemerkt einschleicht.
#!/usr/bin/env bash
# audit-magento-permissions.sh - check Magento webroot ownership and modes
set -euo pipefail
WEBROOT="/var/www/html"
DEPLOY_USER="deploy"
WEB_GROUP="www-data"
echo "[CHECK] Base ownership of the webroot"
find "${WEBROOT}" -maxdepth 1 -not -user "${DEPLOY_USER}" -print
echo "[CHECK] Directories must not exceed 750"
find "${WEBROOT}" -type d -perm /027 -print
echo "[CHECK] Files must not exceed 640"
find "${WEBROOT}" -type f -perm /137 -print
echo "[CHECK] pub/media must never be executable"
find "${WEBROOT}/pub/media" -type f -perm /111 -print
echo "[CHECK] var/ and generated/ must be writable by the web server group"
stat -c "%U:%G %a %n" "${WEBROOT}/var" "${WEBROOT}/generated"
echo "[CHECK] SSH key permissions for the deploy user"
stat -c "%a %n" "/home/${DEPLOY_USER}/.ssh" "/home/${DEPLOY_USER}/.ssh/authorized_keys"
5. Intrusion Prevention mit fail2ban gegen Brute-Force-Angriffe
fail2ban überwacht Log-Dateien in Echtzeit auf wiederkehrende Muster fehlgeschlagener Anmeldeversuche und verhängt nach einer konfigurierbaren Anzahl von Fehlversuchen innerhalb eines Zeitfensters automatisch eine temporäre Firewall-Sperre für die Quell-IP, umgesetzt über iptables, nftables oder direkt über ufw. Für SSH ist die Jail sshd in nahezu jeder Distribution vorkonfiguriert und muss lediglich in /etc/fail2ban/jail.local aktiviert werden, wobei sich maxretry, findtime und bantime an das eigene Risikoprofil anpassen lassen.
Für den Magento-Adminbereich gibt es keine eingebaute Jail, weil fail2ban die Anwendungslogik von Magento nicht kennt. Notwendig ist ein eigener Filter, der den nginx-Access-Log oder ein dediziertes Magento-Log auf fehlgeschlagene POST-Requests gegen die Admin-Login-Route auswertet, typischerweise erkennbar an wiederholten Antworten auf denselben zufällig generierten Admin-Pfad ohne anschließende erfolgreiche Session. Da der Admin-Pfad bei einer sauberen Installation ohnehin nicht /admin, sondern ein zufällig generierter Wert aus admin/url/use_custom_path ist, kombiniert diese Maßnahme zwei Verteidigungslinien: Ratenbegrenzung durch fail2ban und Verschleierung des tatsächlichen Login-Pfads.
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
maxretry = 4
bantime = 2h
[magento-admin-auth]
enabled = true
port = http,https
filter = magento-admin-auth
logpath = /var/www/html/var/log/system.log
/var/log/nginx/access.log
maxretry = 5
findtime = 10m
bantime = 3h
action = %(action_mwl)s
# /etc/fail2ban/filter.d/magento-admin-auth.conf
[Definition]
failregex = ^.*"POST /admin_[a-z0-9]+/admin/index/index.*" 200 .* "<HOST>".*$
ignoreregex =
6. SSH-Härtung: Key-Only-Auth, kein Root-Login, alternativer Port
Die wirksamste einzelne SSH-Maßnahme ist, Passwort-Authentifizierung vollständig abzuschalten: PasswordAuthentication no und PubkeyAuthentication yes in /etc/ssh/sshd_config erzwingen, dass sich niemand mehr ohne einen zuvor hinterlegten privaten Schlüssel anmelden kann. Brute-Force-Angriffe gegen Passwörter, die den Großteil automatisierter SSH-Scans ausmachen, laufen damit ins Leere, unabhängig davon, wie schwach ein einzelnes Nutzerpasswort tatsächlich wäre. Ergänzend gehört PermitRootLogin no gesetzt, sodass ein Angreifer selbst mit einem gültigen Root-Passwort keinen direkten Root-Zugriff über SSH erhält, sondern sich zunächst als regulärer Benutzer anmelden und danach explizit über sudo eskalieren muss, was zusätzlich protokolliert wird.
Das Ändern des Standard-Ports von 22 auf einen anderen Wert wird oft überbewertet und sollte ausschließlich als zusätzliche, nachrangige Maßnahme verstanden werden, nicht als primäre Kontrolle. Der Effekt liegt vor allem darin, das Rauschen automatisierter Massenscanner im Log drastisch zu reduzieren, was die manuelle Auswertung echter Anmeldeversuche erleichtert. Ein gezielter Angreifer, der ein konkretes Ziel bereits im Visier hat, findet einen offenen Port über einen vollständigen Portscan in wenigen Minuten, weshalb ein alternativer Port niemals Key-Only-Auth oder fail2ban ersetzt, sondern diese Maßnahmen nur ergänzt. Wichtig ist zusätzlich, moderne Ciphers- und KexAlgorithms-Listen sowie ein niedriges MaxAuthTries zu konfigurieren.
#!/usr/bin/env bash
# harden-sshd.sh - apply key-only, non-root SSH hardening and validate before reload
set -euo pipefail
SSHD_CONFIG="/etc/ssh/sshd_config"
cp "${SSHD_CONFIG}" "${SSHD_CONFIG}.bak.$(date +%s)"
# Enforce key-only authentication, no root login, low retry budget
sed -i \
-e 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' \
-e 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' \
-e 's/^#\?PermitRootLogin.*/PermitRootLogin no/' \
-e 's/^#\?MaxAuthTries.*/MaxAuthTries 3/' \
"${SSHD_CONFIG}"
# Defense-in-depth only: move off the default port after key-only auth is confirmed working
grep -q '^Port ' "${SSHD_CONFIG}" || echo "Port 2222" >> "${SSHD_CONFIG}"
echo "[CHECK] Validating configuration syntax before reload"
sshd -t
echo "[OK] Reloading sshd with hardened configuration"
systemctl reload sshd
7. Firewall-Grundlagen mit ufw als letzte Verteidigungslinie
Eine Firewall ist die letzte Verteidigungslinie, falls eine der vorherigen Maßnahmen versagt oder ein Dienst versehentlich doch an einer öffentlichen Schnittstelle lauscht. ufw (Uncomplicated Firewall) ist auf Debian- und Ubuntu-Systemen die pragmatische Oberfläche über iptables beziehungsweise nftables und sollte mit einer restriktiven Grundhaltung konfiguriert werden: eingehender Verkehr wird standardmäßig verweigert, ausgehender erlaubt, und nur die tatsächlich benötigten Ports werden explizit freigegeben, üblicherweise 80 und 443 für HTTP/HTTPS sowie der SSH-Port. ufw limit ssh ergänzt fail2ban durch eine einfache, kernelnahe Ratenbegrenzung, die bereits vor der Log-Auswertung durch fail2ban greift.
Ein häufig übersehenes Problem auf Docker-Hosts wie dem Mark-Shust-Setup ist, dass Docker eigene iptables-Regeln in einer separaten Chain einträgt und dabei ufw-Regeln unter Umständen umgeht, sodass ein Container-Port trotz aktiver ufw-Sperre öffentlich erreichbar bleibt. Wer Docker auf einem gehärteten Host betreibt, sollte Port-Bindings in docker-compose.yml explizit auf 127.0.0.1 beschränken, wo kein direkter externer Zugriff nötig ist, und zusätzlich die DOCKER-USER-iptables-Chain nutzen, um Docker-Container gezielt in die ufw-Firewall-Logik einzubinden, statt sich blind auf die Standard-ufw-Regeln zu verlassen.
8. Praktische Hardening-Checkliste für den Magento-Produktivserver
Server-Hardening ist kein einmaliges Setup-Skript, sondern ein wiederkehrender Prozess, der bei jedem neuen Server, jeder Migration und jedem größeren Update erneut durchlaufen werden muss. Für ein Mark-Shust-basiertes docker-magento-Setup empfiehlt sich folgende Reihenfolge: zuerst die minimale Angriffsfläche herstellen, danach automatische Sicherheitsupdates aktivieren, anschließend alle Container- und Systemprozesse auf Non-Root-Ausführung prüfen, danach die Dateisystemrechte im Webroot auditieren, gefolgt von fail2ban-Jails für SSH und Admin-Login, SSH-Härtung und zuletzt der ufw-Firewall als abschließende Kontrollebene. Diese Reihenfolge stellt sicher, dass jede Maßnahme auf einer bereits abgesicherten Basis aufsetzt.
Damit Hardening-Maßnahmen nicht über Monate unbemerkt driften, etwa weil eine manuelle Änderung Dateirechte wieder aufweicht oder ein neuer Container versehentlich als root startet, lohnt sich eine Automatisierung der Audit-Skripte über einen Cron-Job oder eine CI-Pipeline, die regelmäßig gegen eine dokumentierte Baseline prüft. Konfigurationsmanagement-Werkzeuge wie Ansible machen die gesamte Härtung zusätzlich reproduzierbar und versionierbar, sodass ein neu aufgesetzter Server exakt denselben Sicherheitsstand erreicht wie der bestehende, statt sich auf manuell gepflegte Dokumentation zu verlassen, die in der Praxis regelmäßig veraltet.
9. Server-Hardening im direkten Vergleich
Die folgende Übersicht stellt unsichere Standardkonfigurationen den entsprechenden Hardening-Maßnahmen gegenüber, wie sie auf einem typischen Magento-Produktivserver in den vorherigen Abschnitten beschrieben wurden.
| Bereich | Unsicheres Verhalten | Sichere Gegenmaßnahme | Wirkung |
|---|---|---|---|
| Prozess-Rechte | php-fpm/nginx läuft als root | Dedizierter Non-Root-User mit minimalen Rechten | Begrenzt Schaden bei Remote Code Execution |
| SSH-Zugang | Passwort-Login und Root-Login erlaubt | Nur Key-Auth, PermitRootLogin no | Verhindert Brute-Force und direkten Root-Zugriff |
| Patch-Management | Keine automatischen Sicherheitsupdates | unattended-upgrades / dnf-automatic aktiv | Schließt bekannte Lücken zeitnah |
| Dateisystemrechte | var/, generated/, pub/media mit 777 | Korrekte Permissions: 750/640 nach Least-Privilege | Verhindert Web-Shell-Persistenz |
| Brute-Force-Schutz | Kein Intrusion-Prevention gegen Brute-Force | fail2ban-Jails für SSH und Magento-Admin-Login | Automatische Sperre nach Fehlversuchen |
Keine dieser Maßnahmen ersetzt die anderen: Non-Root-Prozesse begrenzen den Schaden nach einer erfolgreichen Kompromittierung, SSH-Härtung und fail2ban verhindern viele Kompromittierungen von vornherein, automatische Updates schließen die Lücken, die sonst überhaupt erst ausgenutzt würden. Erst das Zusammenspiel aller fünf Ebenen ergibt ein Produktivsystem, das gegen die realistischen, breit automatisierten Angriffsmuster im Internet robust ist.
Mironsoft
Server-Hardening-Audits und Infrastruktur-Absicherung für Magento-Produktivsysteme
Euren Magento-Server professionell härten lassen?
Wir auditieren eure Server-Konfiguration, härten SSH- und Dateisystemrechte, richten fail2ban und automatische Sicherheitsupdates ein und dokumentieren die gesamte Konfiguration reproduzierbar.
Server-Audit
Vollständige Prüfung von Diensten, Ports, Prozessrechten und Dateisystem-Berechtigungen
SSH & Firewall
Key-Only-Zugang, ufw-Regeln und fail2ban-Jails für SSH und Magento-Admin
Automatisierung
Reproduzierbare Härtung über Ansible statt manuell gepflegter Dokumentation
10. Zusammenfassung
Server-Hardening ist die Summe vieler kleiner, unspektakulärer Maßnahmen, die zusammen die realistische Angriffsfläche eines Magento-Produktivservers drastisch reduzieren. Eine minimale Grundinstallation ohne unnötige Dienste und Ports, automatische Sicherheitsupdates mit sorgfältig gewählten Ausnahmen, konsequente Non-Root-Ausführung aller Anwendungsprozesse und korrekte Dateisystemrechte bilden das Fundament. Keine dieser Maßnahmen ist für sich genommen spektakulär, aber jede einzelne schließt eine reale, in freier Wildbahn ausgenutzte Angriffsklasse.
fail2ban und SSH-Härtung ergänzen dieses Fundament um aktive Verteidigung gegen Brute-Force-Angriffe, während eine ufw-Firewall als letzte Kontrollebene greift, falls doch einmal ein Dienst versehentlich exponiert wird. Wer diese Maßnahmen nicht als einmaliges Setup, sondern als wiederkehrenden, automatisierten Prozess versteht und etwa über Ansible reproduzierbar macht, betreibt einen Magento-Produktivserver, der den gängigen automatisierten Angriffsmustern im Internet dauerhaft standhält.
Server-Hardening: Das Wichtigste auf einen Blick
Angriffsfläche minimieren
Unnötige Dienste, Ports und Pakete konsequent deaktivieren und entfernen, ss -tulpn regelmäßig prüfen.
Non-Root durchsetzen
php-fpm, nginx und Docker-Container laufen mit dediziertem, unprivilegiertem User statt root.
SSH & fail2ban
Nur Key-Auth, PermitRootLogin no, fail2ban-Jails für SSH und Magento-Admin-Login.
Automatisierte Updates
unattended-upgrades bzw. dnf-automatic mit Security-Origin-Beschränkung und Mail-Benachrichtigung.