Defense in Depth: Sieben Sicherheitsebenen für TYPO3-Produktionsserver

Image Description
Christopher Zechendorf
03.04.2026
Share:

Warum eine einzelne Schutzmassnahme nie ausreicht — und wie wir TYPO3-Produktionsserver mit sieben aufeinander aufbauenden Sicherheitsebenen absichern.

Defense in Depth: Sieben Sicherheitsebenen für TYPO3-Produktionsserver

Die Herausforderung

In einem früheren Beitrag haben wir gezeigt, wie ein einzelner Vulnerability Scanner eine TYPO3-Website lahmlegen konnte — nicht durch einen DDoS-Angriff, sondern durch die Erschöpfung von PHP-FPM-Workern. Das Rate Limit allein reichte nicht aus. Erst die Kombination aus Connection Limiting und fail2ban löste das Problem.

Dieser Fall illustriert ein grundlegendes Prinzip der IT-Sicherheit: Defense in Depth. Keine einzelne Schutzmassnahme ist perfekt. Jede Ebene hat blinde Flecken — was die Firewall nicht sieht, fängt das Rate Limiting ab; was das Rate Limiting nicht erkennt, blockiert die Intrusion Detection. Die Stärke liegt in der Kombination.

Für unsere TYPO3-Produktionsumgebungen setzen wir sieben aufeinander aufbauende Sicherheitsebenen ein, die wir im Folgenden durchgehen.

Sieben Ebenen im Detail

1. Betriebssystem-Härtung

Die erste Verteidigungslinie ist der Server selbst. Über Cloud-Init wird jeder neue Server automatisch mit einer gehärteten Grundkonfiguration provisioniert:

SSH-Härtung:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

Root-Login ist deaktiviert, Passwort-Authentifizierung verboten. Nur Public-Key-Authentifizierung ist erlaubt, mit maximal 3 Fehlversuchen. Inaktive Verbindungen werden nach 10 Minuten getrennt — das verhindert vergessene SSH-Sessions als potenzielle Angriffsfläche.

Firewall (UFW):

ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp

Standardmässig wird jeglicher eingehender Traffic blockiert. Nur drei Ports sind offen: SSH für Administration, HTTP und HTTPS für Web-Traffic. Kein MySQL-Port, kein Redis-Port, kein phpMyAdmin — diese Dienste sind ausschliesslich über die interne Docker-Netzwerkkommunikation erreichbar.

Automatische Sicherheitsupdates: Unattended Upgrades prüfen täglich auf Patches und installieren Sicherheitsupdates automatisch. Bei Kernel-Updates erfolgt ein Reboot um 4:00 Uhr morgens. Docker-Pakete sind von automatischen Updates ausgenommen, da ein unerwartetes Docker-Upgrade laufende Container beeinträchtigen könnte.

2. Netzwerkisolation

Die Docker-Compose-Konfiguration definiert zwei getrennte Netzwerke:

networks:
  backend:
    internal: true
  frontend:

Das backend-Netzwerk ist als internal markiert — Container in diesem Netzwerk haben keinen Zugang zum Internet und sind von aussen nicht erreichbar. MariaDB und Redis befinden sich ausschliesslich in diesem Netzwerk. Nur der TYPO3-Container hat Zugang zu beiden Netzwerken und fungiert als einziger Zugangspunkt.

Warum das wichtig ist: Selbst wenn ein Angreifer Code-Ausführung im TYPO3-Container erlangt, kann er die Datenbank nicht direkt aus dem Internet ansprechen. Es gibt keinen offenen Port, keinen Weg am Application Layer vorbei. Ein nmap-Scan auf dem Host zeigt nur Port 80, 443 und 22 — die Datenbankports existieren auf Netzwerkebene schlicht nicht.

3. TLS-Härtung

Die Verschlüsselung zwischen Browser und Server ist die nächste Schicht:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...';
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

TLS 1.2 und 1.3 ausschliesslich — ältere Versionen mit bekannten Schwächen (POODLE, BEAST) sind deaktiviert. Die Cipher Suite priorisiert Forward Secrecy (ECDHE) und moderne Algorithmen (ChaCha20, AES-GCM).

OCSP Stapling beschleunigt die Zertifikatsprüfung: Statt dass der Browser den Zertifikatsstatus bei der CA abfragen muss, liefert der Server die signierte Bestätigung gleich mit. Das spart einen Roundtrip und verhindert Privacy-Leaks an die CA.

HSTS mit Preload sorgt dafür, dass Browser die Domain ausschliesslich über HTTPS laden — auch beim ersten Besuch, wenn der Nutzer http:// eingibt. Das preload-Flag registriert die Domain in den HSTS-Preload-Listen der Browser, sodass selbst der allererste HTTP-Request nie unverschlüsselt gesendet wird.

Automatische Zertifikats-Verwaltung: Let’s-Encrypt-Zertifikate werden beim Container-Start automatisch angefordert und zweimal täglich per Cron erneuert. Kein manuelles Eingreifen, keine abgelaufenen Zertifikate.

4. Web-Server-Härtung

Nginx bildet die zentrale Verteidigung auf Applikationsebene:

Rate Limiting begrenzt jeden Client auf 5 Requests pro Sekunde mit einem Burst von 15. Das verhindert Brute-Force-Angriffe und bremst automatisierte Scanner. TYPO3-Backend-Dateiuploads (AJAX-Requests) sind vom Rate Limit ausgenommen, damit Redakteure nicht beim Hochladen grosser Dateien blockiert werden.

Blockierte Angriffspfade schliessen bekannte Einfallstore:

# Versteckte Dateien (.env, .git, .htaccess)
location ~ /\.(?!well-known\/) { deny all; }

# PHP-Ausführung in Upload-Verzeichnissen
location ~* ^/(?:fileadmin|typo3conf|typo3temp|uploads)/.*\.php$ { deny all; }

# Konfigurationsdateien und Backups
location ~ /(?:composer\.(?:json|lock)|.*\.(?:bak|conf|cfg|sql|log|sh))$ { deny all; }

# TYPO3-interne Verzeichnisse
location ~ /(?:typo3conf/ext|typo3/sysext)/[^/]+/(?:Resources/Private|Tests)/ { deny all; }

Die Regel für Upload-Verzeichnisse ist besonders kritisch: Wenn ein Angreifer eine PHP-Datei in fileadmin/ hochladen kann (z.B. über eine Schwachstelle im Datei-Upload), wird sie von Nginx nicht an PHP-FPM weitergeleitet, sondern blockiert. Die hochgeladene Datei ist nutzlos.

Security Headers ergänzen den Schutz auf HTTP-Ebene:

X-Content-Type-Options: nosniff      # Verhindert MIME-Type-Sniffing
X-Frame-Options: SAMEORIGIN           # Clickjacking-Schutz
Referrer-Policy: strict-origin-when-cross-origin

Server-Identität verbergen: Der X-Powered-By-Header, den PHP standardmässig sendet, wird über fastcgi_hide_header entfernt. Ein Angreifer soll nicht ohne Weiteres erkennen, welche PHP-Version läuft.

5. Intrusion Detection

fail2ban überwacht die Nginx-Access-Logs und erkennt typische Scanner-Muster:

[Definition]
failregex = ^<HOST> -.*"(GET|POST) /\.env[^\s]* HTTP/.*$
            ^<HOST> -.*"(GET|POST) /wp-(admin|content|includes|json|login)[^\s]* HTTP/.*$
            ^<HOST> -.*"(GET|POST) /xmlrpc\.php[^\s]* HTTP/.*$
            ^<HOST> -.*"(GET|POST) /administrator[^\s]* HTTP/.*$
            ^<HOST> -.*"(GET|POST) /phpmyadmin[^\s]* HTTP/.*$
            ^<HOST> -.*"(GET|POST) /\.git[^\s]* HTTP/.*$

Jede IP, die innerhalb von 60 Sekunden 5 dieser Muster auslöst, wird für eine Stunde per nftables-Firewall-Regel auf allen Ports gesperrt. Der Scanner erhält keinen einzigen Response mehr — nicht einmal ein 403 Forbidden.

Warum nftables statt HTTP-Block? Ein HTTP-Level-Block (z.B. deny in Nginx) verbraucht trotzdem Server-Ressourcen: Nginx muss die Verbindung annehmen, den Request parsen und eine Antwort senden. Eine Firewall-Regel verwirft die Pakete bereits auf Kernel-Ebene, bevor sie den Userspace erreichen. Bei einem aggressiven Scanner spart das messbar CPU-Last.

6. Applikations-Härtung

Innerhalb des Containers ist PHP selbst gehärtet:

OPcache mit 256 MB Speicher und 10.000 gecachten Dateien sorgt dafür, dass PHP-Dateien nur einmal kompiliert werden. Das verbessert nicht nur die Performance, sondern verhindert auch, dass ein zur Laufzeit modifiziertes Script sofort ausgeführt wird — der OPcache liefert die kompilierte Version aus dem Speicher, bis revalidate_freq erreicht ist.

Ressourcen-Limits auf Container-Ebene verhindern, dass ein einzelner Service den gesamten Server lahmlegt. Die Limits werden vom Setup-Script berechnet und als Docker deploy.resources gesetzt:

deploy:
  resources:
    limits:
      memory: 2G
      cpus: "1.1"
    reservations:
      memory: 819M

Überschreitet ein Container sein Memory-Limit, wird er von Docker beendet und automatisch neu gestartet (restart: unless-stopped). Das ist besser als ein OOM-Kill auf Host-Ebene, der unkontrolliert Prozesse beenden könnte.

PHP-FPM Worker-Berechnung: Die Anzahl der Worker wird automatisch an den verfügbaren Speicher angepasst — ein Worker pro 80 MB. Das verhindert sowohl Worker-Erschöpfung (zu wenige) als auch Speicherüberläufe (zu viele).

7. Monitoring und Log-Management

Die letzte Ebene stellt sicher, dass Probleme erkannt werden, bevor sie zu Ausfällen führen:

Health Checks überwachen die Dienste. Redis wird alle 10 Sekunden per redis-cli ping geprüft. Nach 5 fehlgeschlagenen Checks startet Docker den Container automatisch neu.

Log Rotation verhindert, dass Logs die Festplatte füllen:

  • PHP-Fehler: wöchentlich rotiert, 8 Wochen Aufbewahrung
  • TYPO3-Logs: täglich rotiert, 14 Tage Aufbewahrung
  • Docker-Container-Logs: maximal 10 MB pro Datei, 3 Dateien pro Service

Scheduler-Lock-Reset: Beim Container-Start werden alle blockierten TYPO3-Scheduler-Tasks zurückgesetzt. Wird ein Container während eines laufenden Cronjobs beendet (z.B. bei einem Deployment), bleiben die Tasks sonst dauerhaft als “running” markiert und werden nie wieder ausgeführt. Der Entrypoint-Script erkennt diesen Zustand und bereinigt ihn automatisch.

Das Zusammenspiel

Die Stärke von Defense in Depth liegt nicht in der einzelnen Massnahme, sondern im Zusammenspiel:

Angriffsvektor Ebene 1–2 Ebene 3–4 Ebene 5–7
SSH-Brute-Force UFW + SSH-Härtung fail2ban sperrt nach 3 Versuchen
Vulnerability Scanner Firewall blockiert unbekannte Ports Rate Limiting bremst, Pfade blockiert fail2ban sperrt per Muster
Hochgeladene PHP-Shell Nginx blockiert PHP in Upload-Dirs Logs zeigen den Versuch
SQL Injection Netzwerkisolation begrenzt Schaden Container-Limits verhindern Eskalation
Abgelaufenes Zertifikat Automatische Erneuerung Certbot-Logs bei Fehler

Selbst wenn eine Ebene versagt, greifen die anderen. Ein Scanner, der das Rate Limit unterläuft (wie in unserem dokumentierten Fall), wird trotzdem von fail2ban erkannt. Ein PHP-Prozess, der ausser Kontrolle gerät, wird durch das Container-Memory-Limit begrenzt.

Fazit

Sicherheit ist kein Feature, das man einmal konfiguriert. Es ist ein System aus sich ergänzenden Massnahmen, das regelmässig überprüft und erweitert wird. Unser Boilerplate automatisiert dieses System, sodass jedes neue Projekt automatisch alle sieben Ebenen erhält — ohne manuellen Aufwand und ohne die Möglichkeit, eine Ebene zu vergessen.

Die hier beschriebenen Massnahmen sind nicht TYPO3-spezifisch. Dieselben Prinzipien gelten für jede PHP-Anwendung hinter Nginx — ob WordPress, Symfony oder Laravel. Der Ansatz ändert sich nicht, nur die Applikationsschicht.


Möchten Sie wissen, wie gut Ihre aktuelle Server-Konfiguration gegen diese Angriffsvektoren geschützt ist? Wir analysieren Ihre Infrastruktur und identifizieren Lücken. Nehmen Sie über unser Kontaktformular unverbindlich Kontakt mit uns auf.

Interesse geweckt? Top-Stories direkt in Ihre Mailbox:

Share:

Über den Autor

Christopher Zechendorf

Christopher Zechendorf

Christopher Zechendorf leitet die ext.dev GmbH und bringt über 25 Jahre Erfahrung in Webentwicklung, CMS-Systemen und Infrastruktur mit.