Sicherheitsprüfung 2 – Zusammenfassung des gesamten Verlaufs
1. Ausgangspunkt
Im CMS gab es zunächst einen Tokenfehler beim Logo-Upload. Ziel war, diesen Fehler zu prüfen und zusätzlich einen allgemeinen Sicherheitscheck für das System durchzuführen.
2. CSRF-Problem beim Upload
Die Ursache war, dass der globale CSRF-Check vor dem Multipart-Parsing durch multer ausgeführt wurde. Dadurch war bei Uploads mit multipart/form-data das Feld _csrf noch nicht verfügbar.
Das betraf zuerst den Logo-Upload und später auch die Download-Uploads.
Gelöste Punkte
- CSRF-Upload-Bug wurde behoben
- Logout-Cookie wurde korrigiert
- 500.hbs wurde angelegt
3. Fehler in admin.js
Danach trat ein weiterer Fehler auf:
ReferenceError: verifyCsrfToken is not defined
Die Ursache war ein fehlender Import von verifyCsrfToken in admin.js. Das wurde behoben.
4. Download-Uploads prüfen
Als nächstes wurde der Bereich Download-Uploads geprüft. Relevant waren dabei:
- server.js
- src/routes/admin.js
- src/middleware/csrf.js
- src/utils/downloadUpload.js
- src/services/downloadService.js
- views/admin/download-form.hbs
Feststellungen
Die HBS-Datei war grundsätzlich korrekt. Das Problem lag nicht im Formular selbst, sondern wieder in der Kombination aus:
- globalem CSRF-Check
- Multipart-Upload
- und nachgelagerter Verarbeitung
5. Missverständnis bei Datei URL / Externe URL
Im Download-Formular war das Feld Datei URL missverständlich. Es wurde klargestellt:
- Bei lokalem Datei-Upload bleiben Datei URL und Externe URL leer.
- Diese Felder sind nur für externe Dateien bzw. Weiterleitungen gedacht.
6. Problem mit Dateinamen und Endungen
Danach wurde festgestellt, dass beim Download die Datei zwar ausgeliefert wurde, aber teils ohne Endung oder mit unpassendem Namen.
Daraufhin wurde downloadService.js angepasst, damit:
- die Endung erhalten bleibt
- bzw. notfalls anhand von MIME-Type oder Dateiname ergänzt wird
- und der ausgelieferte Dateiname für den Nutzer sauber bleibt
7. CSS-Struktur in download-form.hbs
Zwischendurch wurde die CSS-Struktur der download-form.hbs unbeabsichtigt kaputtgemacht, weil andere Klassennamen eingeführt wurden.
Das wurde korrigiert, indem die Datei wieder an die bestehenden Klassen angepasst wurde, z. B.:
- alert error
- form-grid
- form-row
- full
- checkbox-row
8. 404 beim Download
Trotz korrekter Speicherung kam beim Download weiterhin ein 404-Fehler.
Es wurde geprüft:
- Public-HBS / Download-Detail-Seite
- routes/downloads.js
- models/downloadModel.js
- models/downloadTokenModel.js
- routes/download-token.js
Erkenntnisse
Die Public-HBS war nicht das Problem. Die Route /downloads/:slug/generate funktionierte ebenfalls korrekt und erzeugte einen Token. Der 404 trat erst im Bereich /dl/:token auf.
9. Prüfung der Token-Tabelle
Es wurde direkt in der Datenbank geprüft, ob die Token korrekt gespeichert werden.
Ergebnis:
- token_len = 64 → korrekt
- used_at = NULL → korrekt
- expires_at lag in der Zukunft → korrekt
Damit war klar, dass weder die Tokenlänge noch die Speicherung selbst das eigentliche Problem waren.
10. Der echte Fehler: Zeitprüfung des Tokens
Die Konsole zeigte:
DOWNLOAD TOKEN RESOLVED: NO
Dadurch wurde klar, dass der Token zwar gespeichert, aber von resolveDownloadToken() nicht wieder als gültig erkannt wurde.
Die Ursache war die SQL-Prüfung in downloadTokenModel.findValidToken():
WHERE token = ?
AND used_at IS NULL
AND expires_at >= NOW()
Hier hing die Gültigkeit am NOW() der Datenbank. Das führte dazu, dass der Token direkt als ungültig behandelt wurde, obwohl er gerade frisch erzeugt worden war.
11. Lösung des Token-Problems
Die Lösung war:
- in downloadTokenModel.js nicht mehr direkt per SQL auf NOW() prüfen
- stattdessen den Token-Datensatz per findByToken() laden
- und die Prüfung von used_at und expires_at in Node.js durchführen
Dadurch wurde die Gültigkeitsprüfung konsistent und unabhängig von DB-Zeitverschiebungen.
12. Pfad- und Dateispeicher-Thema
Zusätzlich wurde geklärt, dass der Upload-Pfad nicht über process.cwd(), sondern sauber relativ zur Datei aufgebaut werden soll:
__dirname = /app/src/utils
→ /app/storage/downloads
So ist der Speicherpfad stabil und unabhängig davon, von wo Node gestartet wurde.
13. Verhalten bei Dateinamen
Es wurde außerdem festgelegt:
- Der Token-Link darf kryptisch sein.
- Die Datei auf dem Server soll nicht unnötig durch einen Token-Namen ersetzt werden.
- Die interne Zuordnung läuft über den Datensatz und stored_filename.
- Der Token selbst darf sich bei jedem Aufruf neu ändern.
14. Erfolgreicher Abschluss
Nach der Anpassung von downloadTokenModel.js und downloadService.js funktionierte der Download wieder korrekt.
Anschließend wurden die temporären Debug-Logs aus download-token.js wieder entfernt.
15. Sicherheitsbewertung allgemein
Zusätzlich zum akuten Bug wurden weitere Sicherheitsaspekte angesprochen:
- Session-Store statt Memory-Store
- Security-Header / CSP
- Upload-Härtung
- Validierung von URL-Feldern
- Passwortregeln
- sauberes Fehlerhandling
16. Endstatus
Aktuell gelöst:
- CSRF-Fehler beim Logo-Upload
- CSRF-Probleme bei Download-Uploads
- fehlender verifyCsrfToken-Import
- Logout-Cookie
- 500-View
- Endungs-/Dateinamensproblem beim Download
- Token-Validierungsproblem durch SQL NOW()
- Debug-Logs wieder bereinigt