From 9adebd9bc4ceeecbd2f067b72b015bc2cd7a0b35 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Thu, 20 Aug 2026 12:47:36 +0200 Subject: [PATCH] KRITISCH: Server-Quellcode + kompletter Git-Verlauf waren oeffentlich abrufbar Sicherheits-Audit vor dem geplanten oeffentlichen Start morgen (21.08.2026, Nutzer-Anfrage: "duerfen die leute keinen zugriff auf veraenderungen haben"). SITE_DIR ist der GESAMTE Repo-Ordner (join(__dirname, "..")), express.static lieferte daher nicht nur die Website aus, sondern auch: - server/ (inkl. gate.js, das komplette Sicherheitskonzept im Klartext) - server-internal/ (Admin-/Supporter-Backend-Quellcode) - cloudflare-worker/ (altes Backend) - .git/ (VOLLSTAENDIGE Commit-Historie, rekonstruierbar per Git-Dump) - CLAUDE.md, DEPLOY.md, wrangler.toml, netlify.toml, gate-worker.js, gate.html.bak-07-08-2026 (Alt-Backup-Datei einer frueheren Session) Live nachgewiesen (mit gueltigem Zugangscode -- morgen faellt die Schranke fuer ALLE weg): /server/gate.js und /.git/config lieferten HTTP 200. Ursache: serve-static blockt per Default nur Dateien, deren EIGENER Name mit einem Punkt beginnt (server/.env -> zufaellig schon 404), aber NICHT rekursiv -- .git/config wird trotzdem ausgeliefert, weil "config" selbst nicht mit einem Punkt beginnt, nur der Ordner davor. Fix: eigene Sperr-Middleware VOR express.static, unabhaengig von gateMiddleware (bleibt also auch nach dem Entfernen der Zugangsschranke wirksam). Blockt ganze Ordner (server/, server-internal/, cloudflare-worker/) + versteckte Ordner/Dateien rekursiv (jedes Pfadsegment, das mit "." beginnt, ausser .well-known) + eine feste Liste an Alt-Dateien + jedes *.bak-Muster, damit auch kuenftige Backup-Reste automatisch mitgeschuetzt sind. Lokal mit echtem Express-Server verifiziert (gateMiddleware absichtlich deaktiviert, um exakt den morgigen "oeffentlich"-Zustand zu simulieren): alle vorher gefundenen Luecken jetzt 404, alle echten Seiten/Assets (index.html, main.css, main.js, manifest.json, robots.txt, favicon) weiterhin 200. Getrennt prooft: server-internal/ (eigener Dienst unter postfach.dogfather-universe.com, Port 4200) hat sein EIGENES, unabhaengiges Session-System -- jede /admin/*-Route ist einzeln per requireTeamSession-Middleware abgesichert (in index.js durchgezaehlt, keine Ausnahme gefunden), live mit einer unauthentifizierten Anfrage gegen /admin/users/list bestaetigt (401). Dieser Dienst war nie vom Website-Gate abhaengig und ist von diesem Fund nicht betroffen. Co-Authored-By: Claude Opus 5 --- server/index.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/server/index.js b/server/index.js index d8e22012..4a70f314 100644 --- a/server/index.js +++ b/server/index.js @@ -37,6 +37,40 @@ app.use(cookieParser()); app.use(express.json({ limit: "1mb" })); app.use(gateMiddleware); +/* Sicherheits-Fix 20.08.2026 (Audit vor dem geplanten öffentlichen Start morgen). + SITE_DIR ist der GESAMTE Repo-Ordner (join(__dirname, "..")) — express.static liefert + ohne diese Sperre daher nicht nur die eigentliche Website aus, sondern auch den Server- + Quellcode (server/, server-internal/, cloudflare-worker/) und das komplette + .git-Verzeichnis samt Commit-Historie. + Live nachgewiesen (mit gültigem Zugangscode, der morgen für alle wegfällt): + /server/gate.js und /.git/config lieferten HTTP 200. Ursache: serve-static blockt per + Voreinstellung nur Dateien, deren EIGENER Name mit einem Punkt beginnt (server/.env -> + 404 durch diese Regel) — aber NICHT rekursiv. Eine Datei wie .git/config wird trotzdem + ausgeliefert, weil "config" selbst nicht mit einem Punkt beginnt, nur der Ordnername davor. + Diese Sperre läuft daher bewusst unabhängig von gateMiddleware (bleibt auch nach dem + morgigen Entfernen der Zugangsschranke wirksam) und blockt ganze Ordner/Muster statt + einzelner Dateien, damit neue Dateien darin automatisch mitgeschützt sind. */ +const GESPERRTE_ORDNER = ["/server", "/server-internal", "/cloudflare-worker"]; +const GESPERRTE_DATEIEN = [ + "/CLAUDE.md", "/DEPLOY.md", "/wrangler.toml", "/netlify.toml", + "/gate-worker.js", "/_headers", "/.gitignore", "/.nojekyll", "/.assetsignore", +]; +app.use((req, res, next) => { + const pfad = req.path; + const hatVerstecktenOrdner = pfad + .split("/") + .some((teil) => teil.startsWith(".") && teil.length > 1 && teil !== ".well-known"); + const inGesperrtemOrdner = GESPERRTE_ORDNER.some((p) => pfad === p || pfad.startsWith(p + "/")); + const istGesperrteDatei = GESPERRTE_DATEIEN.includes(pfad); + const istBackupDatei = /\.bak(-|\.|$)/i.test(pfad); + if (hatVerstecktenOrdner || inGesperrtemOrdner || istGesperrteDatei || istBackupDatei) { + return res.status(404).sendFile(join(SITE_DIR, "404.html"), (err) => { + if (err) res.status(404).send("Nicht gefunden."); + }); + } + next(); +}); + app.use(express.static(SITE_DIR, { index: "index.html" })); app.use((req, res) => {