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.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user