Zum Inhalt springen
SHIELDMYSERVER

Die Webanwendung härten, ohne den Quelltext zu kennen

Sicherheits-Header, Rechte im Verzeichnisbaum, Upload-Ordner ohne Ausführung und ein Reverse-Proxy, der die Anwendung abschirmt, Maßnahmen, die auch bei fremder Software greifen.

mittelDiesen Monat. Wichtig, aber kein Feuer.

veröffentlicht 19.08.2026 · 2 min

Titelbild: Die Webanwendung härten, ohne den Quelltext zu kennen

Die meisten Anwendungen auf einem Server hat man nicht selbst geschrieben: Shop, Ticketsystem, Wiki, CMS, ein Werkzeug aus einem Container. Der Quelltext ist fremd, die Lücke darin unbekannt und trotzdem entscheidet die Umgebung darum, wie weit ein Treffer trägt.

Warum mittel

Nichts davon schließt eine Lücke in der Anwendung. Alles davon verändert, was ein erfolgreicher Treffer anrichtet: ob aus einer hochgeladenen Datei ausführbarer Code wird, ob der Angreifer den Anwendungscode dauerhaft verändern kann, ob er die Datenbank von außen erreicht.

1. Rechte: Der Webserver darf lesen, nicht schreiben#

Die häufigste Fehlkonfiguration ist ein Verzeichnisbaum, der komplett dem Webserver-Benutzer gehört. Dann macht jede Ausführungslücke den Code dauerhaft veränderbar, die Hintertür überlebt jeden Neustart.

# Eigentümer: Bereitstellungskonto. Gruppe: Webserver. Schreiben: nur wo nötig.
sudo chown -R deploy:www-data /var/www/app
sudo find /var/www/app -type d -exec chmod 750 {} \;
sudo find /var/www/app -type f -exec chmod 640 {} \;

# Genau die Verzeichnisse, in die die Anwendung schreiben muss
sudo chown -R www-data:www-data /var/www/app/var/cache /var/www/app/public/uploads
sudo chmod 770 /var/www/app/var/cache /var/www/app/public/uploads

Gegenprobe: Was gehört dem Webserver, obwohl es Code ist?

sudo find /var/www/app -user www-data -name '*.php' -o -user www-data -name '*.js' | head

2. Uploads dürfen nicht ausführbar sein#

location ^~ /uploads/ {
    # Nichts wird hier interpretiert, egal wie die Datei heißt
    location ~ \.(php|phar|phtml|cgi|pl|py)$ { deny all; return 404; }
    add_header Content-Disposition "attachment" always;
    add_header X-Content-Type-Options "nosniff" always;
}

Besser noch: Uploads liegen außerhalb des Web-Wurzelverzeichnisses und werden von der Anwendung ausgeliefert. Dann existiert kein direkter Pfad, unabhängig von der Konfiguration.

3. Sicherheits-Header, die tatsächlich etwas tun#

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'" always;
CSP nicht blind kopieren

Eine Content-Security-Policy, die zu eng ist, bricht die Anwendung an Stellen, die niemand testet, Zahlungsfenster, Kartenansichten, eingebettete Videos. Erst mit Content-Security-Policy-Report-Only und einer Berichtsadresse fahren, die Verstöße zwei Wochen sammeln, dann scharf schalten. Strict-Transport-Security wirkt umgekehrt lange nach: Der Header bleibt beim Browser gespeichert, auch wenn man es sich anders überlegt.

Prüfen von außen, nicht in der Konfiguration lesen:

curl -sSI https://example.org/ | grep -iE 'strict-transport|content-security|x-content-type|referrer|x-frame'

4. Der Proxy davor trennt sauber#

Eine Anwendung, die nur auf 127.0.0.1 hört und hinter einem Reverse-Proxy steht, gewinnt vier Dinge auf einmal: TLS an genau einer Stelle, Rate-Limits für teure Pfade, saubere Protokolle, und die Möglichkeit, eine Lücke zu entschärfen, ohne die Anwendung anzufassen.

location /admin/ {
    allow 10.99.0.0/24;      # Verwaltung nur aus dem Overlay
    deny all;
    proxy_pass http://127.0.0.1:3000;
}

Genau dieser Block ist im Ernstfall die Zwischenmaßnahme aus Ausgenutzt schlägt kritisch: Wenn ein Patch drei Tage braucht, ist der Pfad in zehn Minuten unerreichbar.

5. Was die Anwendung selbst mitbringt#

Vier Einstellungen, die fast jede Software hat und die fast nie geprüft werden:

  • Standardkonto und Standardpasswort, vorhanden? entfernt?
  • Installationsverzeichnis (/install, /setup), nach der Einrichtung gelöscht?
  • Debug-Modus, in der Produktivumgebung aus? Fehlerseiten ohne Pfade und Versionsnummern?
  • Registrierung offen, obwohl sie geschlossen sein sollte?
for p in /install /setup /admin /.env /debug /phpinfo.php; do
  printf '%s %s\n' "$(curl -sS -o /dev/null -w '%{http_code}' "https://example.org$p")" "$p"
done

6. Und danach: hinsehen#

Eine gehärtete Anwendung, die niemand beobachtet, meldet ihren Einbruch nicht. Die Zugriffsprotokolle des Proxys sind dafür die beste Quelle, sie zeigen die Anfragen, bevor die Anwendung sie interpretiert.

# Auffällige Muster der letzten Stunde
awk -v seit="$(date -d '-1 hour' '+%d/%b/%Y:%H')" '$4 ~ seit' /var/log/nginx/access.log \
  | grep -Ei '\.(php|env|git|sql)|union.*select|\.\./' | head -20

Was daraus ein Alarm wird, steht in Alarme, die nachts ankommen; die Rechte-Grundlagen dazu in Rechte, die nur so weit reichen wie nötig.

MRMedia

Geschrieben aus dem laufenden Betrieb: MRMedia betreibt eigene Hosts, Kundendienste und deren Härtung in der EU. Eine veraltete Anleitung ist hier ein Sicherheitsproblem, kein Schönheitsfehler. Korrekturen bitte über Discord.