Files
nexarch/mail/docs/QA-04-PRUEFPROTOKOLL.md
T
sysops 0505351e8f feat(mail): QA-04 Sicherheits-/Berechtigungsprüfung — fehlenden SMTP-Idle-Timeout gefunden und behoben
Gezielter Testangriff auf den SMTP-Pfad deckte einen realen
Härtungsfehler auf: ING-07 (Idle-Timeout via protoguard) wurde
versehentlich nur in mail/internal/imap und mail/internal/pop3
verdrahtet, SMTP bekam nie einen Timeout. Eine Gegenstelle, die eine
Kommandozeile ohne abschließendes CRLF öffnet und nie beendet, konnte
die Session unbegrenzt blockieren — real reproduziert und danach
behoben.

session.go/server.go (smtp): guard *protoguard.Guard neu, Timeout wird
in readLine() selbst gesetzt (ein Ort für Haupt-Serve-Schleife,
handleData, drainUntilDot). Neuer Konstruktor
NewServerWithMaxMessageBytesTLSLoggerRateLimitAndGuardConfig für
abweichende Timeout-Werte. Bestehende Konstruktoren bekommen automatisch
protoguard.DefaultConfig() (5 Minuten) statt wie zuvor gar keinen
Timeout — reine Härtung, keine Verhaltensänderung für funktionierende
Clients, QA-07-Lasttest bleibt unverändert grün.

Neue Tests: qa04_security_test.go (Header-Injection-Angriffe auf
Envelope-Adressen, Ressourcenerschöpfung durch nie abgeschlossene Zeile
— deckte den Fehler auf und bestätigt die Korrektur).
mailboxconfig/tenant_scoping_test.go: Stichprobe eines dritten
Speicherpfads (verschlüsselte IMAP-Zugangsdaten) — Zugriff mit echter,
bekannter fremder ID wird über alle vier Operationen zuverlässig
abgelehnt.

Rate-Limiting-Teil von Akzeptanzkriterium 3 real bestätigt (ING-09,
erneut mitgeprüft). API-Token-Teil bleibt offen: das Mail-Board besitzt
keine eigene Token-Authentifizierung, bewusst an Core-Board IAM
delegiert (QA-04s eigene Ausgangslage) — im Prüfprotokoll dokumentiert.

go build/go vet/golangci-lint clean, gesamtes Mail-Modul
regressionsfrei getestet.
2026-09-01 14:24:56 +02:00

6.8 KiB
Raw Blame History

QA-04 — Sicherheits- & Berechtigungsprüfung: Prüfprotokoll

Datum: 2026-09-01 Host: 192.168.1.131 (Build/Test/Lint), rsync + ssh Geprüfte Pakete: mail/internal/smtp, mail/internal/mailer, mail/internal/storage, mail/internal/folderstate, mail/internal/mailboxconfig, mail/internal/ratelimit

Umsetzung — echter Sicherheitsbefund und Korrektur

Der gezielte Testangriff auf den SMTP-Pfad (Pflichtprüfung 1) deckte einen REALEN Härtungsfehler auf, der VOR dieser Kachel unbemerkt geblieben war: ING-07 (Idle-Timeout-Schutz) hatte protoguard nur in mail/internal/imap und mail/internal/pop3 verdrahtet — mail/ internal/smtp bekam versehentlich NIE einen Idle-Timeout. Eine Gegenstelle, die eine Kommandozeile ohne abschließendes CRLF öffnet und nie beendet, konnte die Session unbegrenzt blockieren (bestätigt durch TestQA04_OversizedLineWithoutCRLFDoesNotHangOrCrash, VOR der Korrektur real reproduziert: Server antwortete nach 8s Wartezeit weder mit Fehler noch Verbindungsende).

Korrektur (session.go/server.go, mail/internal/smtp): guard *protoguard.Guard als neues Feld, Idle-Timeout wird jetzt in readLine() selbst gesetzt — EIN Ort für alle Aufrufer (Haupt-Serve- Schleife, handleData, drainUntilDot), damit auch das Lesen des DATA-Bodys geschützt ist. Neuer Konstruktor NewServerWithMaxMessageBytesTLSLoggerRateLimitAndGuardConfig für abweichende Timeout-Werte (Tests). Bestehende Konstruktoren bekommen automatisch protoguard.DefaultConfig() (5 Minuten) statt wie zuvor gar keinen Timeout — reine Härtung, keine Verhaltensänderung für funktionierende Clients.

Pflichtprüfung 1: Gezielter Testangriff auf Header-Injection schlägt fehl

TestQA04_HeaderInjectionViaEnvelopeAddressRejected (smtp/qa04_security_test.go): NUL-Byte und Steuerzeichen in RCPT TO/MAIL FROM werden mit 553/501 zurückgewiesen, Session bleibt danach funktionsfähig, keine Nachricht erreicht den Sink. Ergänzt um TestQA04_OversizedLineWithoutCRLFDoesNotHangOrCrash (Ressourcen- erschöpfungsangriff, siehe Abschnitt "Umsetzung" — deckte den realen Härtungsfehler auf und bestätigt nach der Korrektur zuverlässige Reaktion binnen des konfigurierten Timeouts). Bereits bestehende, unverändert gültige Nachweise aus ING-03/ING-06 werden mitgezählt: CRLF-Injection in Betreff/Anzeigename (mailer.TestHeaderWriter_ RejectsControlCharsAndCRLFInSubjectAndDisplayName), Dot-Stuffing korrekt gegen DATA-Command-Smuggling (smtp.TestData_ MessageSizeCheckedBeforeAcceptance u. a.), TLS-Downgrade-Angriffe (smtp.TestServer_RejectsLegacyTLSVersionAndWeakCiphers, ING-06).

Ergebnis: BESTANDEN — inklusive eines real gefundenen und behobenen Härtungsfehlers.

Pflichtprüfung 2: Stichprobenprüfung mehrerer Speicherpfade auf Mandantentrennung

Drei unabhängige Speicherpfade stichprobenartig geprüft:

  1. Objekt-Storage (mail/internal/storage, ARC-06): physische Bucket-Trennung, bereits real gegen MinIO nachgewiesen (TestProvisionTenant_CreatesPhysicallySeparateBuckets, TestAccessWithoutTenantContext_FailsBecauseNoBucketReferenceable — siehe ARC-06-PRUEFPROTOKOLL.md).
  2. Folder-State (mail/internal/folderstate, ING-10): NextUID/Rebuild für Mandant A verändern Mandant Bs Zustand nachweislich nicht (TestTenantScoping_ NeverReturnsOrMutatesOtherTenantsFolderState).
  3. Postfachkonfiguration (mail/internal/mailboxconfig) — NEU für diese Kachel, bislang nicht auditiert, besonders sensibel (verschlüsselte IMAP-Zugangsdaten): TestTenantScoping_ ForeignKnownIDNeverAccessible — Mandant B versucht mit einer ECHTEN, bekannten ID aus Mandant As Zeile (realistischster Angriffsfall bei fortlaufenden IDs in einer gemeinsamen Tabelle) auf List/GetDecryptedPassword/Update/Delete zuzugreifen — jeder Versuch liefert ErrNotFound, Mandant As Daten bleiben unverändert.

Ergebnis: BESTANDEN in allen drei gezogenen Stichproben.

Pflichtprüfung 3: Test: API-Zugriff mit widerrufenem/fremdem Token wird verweigert

Teilweise nicht durchführbar, dokumentiert: Das Mail-Modul besitzt aktuell KEINE eigene HTTP-API mit Token-/Session-Authentifizierung — jede vorhandene Schnittstelle (web/mail-search, SRC-04) verweist explizit auf eine noch ausstehende "zentrale Session-/IAM-Anbindung (Core-Board-Scope, nicht Bestandteil dieser Kachel)", konsistent mit QA-04s eigener Ausgangslage: "Berührt Login-Tenant-Filter und Privilege-Escalation dafür ist bereits Core-Board IAM zuständig, hier nur Mail-spezifische Aspekte prüfen." Es gibt daher keinen Prüfgegenstand für "widerrufenes/fremdes API-Token" innerhalb des Mail-Boards — dieser Teil bleibt offen, bis Core-Board IAM eine Token-Schnittstelle liefert, gegen die geprüft werden kann.

Der Rate-Limiting-Teil von Akzeptanzkriterium 3 ist dagegen real vorhanden und geprüft (ING-09): TestRateLimit_ LoadExceedingLimitGetsRejectedWithRetryHint, TestRateLimit_LegitUsageBelowThresholdUnaffected, TestRateLimit_PerTenantIndependentAndEffective — je einmal in IMAP, POP3, SMTP, alle mit echten Nachweisen bestanden (siehe ING-09-PRUEFPROTOKOLL.md), hier erneut mitgeprüft und bestätigt grün.

Ergebnis: Rate-Limiting-Teil BESTANDEN, API-Token-Teil OFFEN (kein Prüfgegenstand im Mail-Board vorhanden).

Akzeptanzkriterien

  1. Prüfung bestätigt wirksame Härtung des SMTP-Pfads gegen bekannte Angriffsmuster: durch Pflichtprüfung 1 belegt — inklusive eines real gefundenen und in dieser Kachel behobenen Härtungsfehlers (fehlender Idle-Timeout).
  2. Prüfung bestätigt lückenlose Mandantentrennung im Speicherpfad: durch Pflichtprüfung 2 belegt (drei Speicherpfade, keine Lücke gefunden).
  3. Prüfung bestätigt korrekt greifendes API-Token-/Rate-Limiting: Rate-Limiting-Teil durch Pflichtprüfung 3 belegt; API-Token-Teil bleibt offen (kein Prüfgegenstand, siehe oben).

Build/Vet/Lint/Test — Gesamtmodul

go build ./...    → OK
go vet ./...      → OK
golangci-lint run ./... → 0 issues
go test ./... -p 1 (TEST_TENANT_DSN, TEST_MANTICORE_URL, TEST_S3_ENDPOINT/TEST_S3_ACCESS_KEY/TEST_S3_SECRET_KEY gesetzt) → alle Pakete ok

Keine Regression — insbesondere QA-07-Lasttest für SMTP bleibt nach der Idle-Timeout-Korrektur unverändert grün (6057,8 Sessions/s, p95 48,2ms).

Ergebnis

QA-04 erfüllt Akzeptanzkriterium 1 und 2 vollständig mit echten, ausgeführten Nachweisen — inklusive eines real gefundenen und behobenen Sicherheitsfehlers (fehlender SMTP-Idle-Timeout). Akzeptanzkriterium 3 ist zur Hälfte (Rate-Limiting) erfüllt; die API-Token-Hälfte bleibt offen, da im Mail-Board kein Prüfgegenstand existiert (bewusst an Core-Board IAM delegiert, siehe QA-04s eigene Ausgangslage). Board wird auf Basis der erfüllbaren Teile fortgeführt, das offene Element ist hier und im Entscheidungsverlauf vermerkt. Freigeschaltet: QA-09.