Voller Merge von RBAC-02/IAM-06/IAM-07/API-03/API-10/API-08/API-09/IAM-10/ IAM-11/IAM-13 plus echte Angriffstests (internal/pentest) gegen SSO/OIDC (alg=none, Fremdschluessel, Claims-Manipulation, Nonce-Replay), Rate- Limiting/Lockout im simulierten Mehrinstanz-Betrieb, zentrale Policy- Durchsetzung (Rechteausweitung, struktureller Guard-Bypass) und Master- Key-/Tenant-KEK-Rotation. 29/29 Pakete gruen auf 192.168.1.131. Vier real gefundene Testinfrastruktur-Fehler behoben: reset-test-env.sh liess tenant_keks (und weitere neuere Registry-Tabellen) beim Reset stehen (FK-CASCADE loescht nur die Constraint, keine Zeilen); zwei E2E-Tests und kek_test.go schlossen ihren adminPool per defer VOR ihrer t.Cleanup- Bereinigung (t.Cleanup laeuft immer nach allen defers); migrate_test.go hatte ein Testschema ohne die TEN-04-Lifecycle-Spalten. Alle vier Fixes betreffen ausschliesslich Testcode, kein Produktionscode geaendert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
8.9 KiB
QA-04 – Prüfprotokoll: Sicherheits- & Penetrationsprüfung Core
Welle 6. Voraussetzung: RBAC-02, IAM-06, IAM-07, API-03, API-10, API-08,
API-09, IAM-10, IAM-11, IAM-13 (alle Status "Fertig"). Branch:
feature/qa-04-sicherheits-penetrationspruefung-core, alle 10 Vorbedingungen
real gemergt (kein isolierter Cherry-Pick).
1. Gezielte Angriffsversuche und Ergebnis
Alle Tests in internal/pentest/qa04_pentest_test.go, echte Angriffe gegen
die tatsächlichen Produktionspakete, nicht gegen Mocks.
1.1 SSO/OIDC gegen Token-Manipulation, Replay, Claims-Manipulation (Akzeptanzkriterium 1)
| Angriff | Test | Zielwert | Ergebnis |
|---|---|---|---|
alg=none-Angriff gegen externen OIDC-Verifier (IAM-06) |
TestPentest_OIDC_AlgNoneAttack |
abgewiesen | bestanden |
Signatur mit fremdem (Angreifer-)Schlüssel unter bekannter kid |
TestPentest_OIDC_ForeignKeySignature |
abgewiesen | bestanden |
Claims nachträglich manipuliert (Rechteausweitung roles), alte Signatur wiederverwendet |
TestPentest_OIDC_TamperedClaims |
abgewiesen | bestanden |
| Replay eines gültigen ID-Tokens mit abweichendem Nonce | TestPentest_OIDC_NonceReplay |
abgewiesen | bestanden |
Core als eigener IdP (IAM-13): ID-Token mit Angreiferschlüssel unter vorgetäuschter kid |
TestPentest_OIDC_IdPTokenManipulation |
abgewiesen | bestanden |
Ergebnis: internal/oidc.Verifier erzwingt Algorithmus (RS256 bzw.
EdDSA), prüft Signatur ausschließlich gegen den unter der kid tatsächlich
registrierten Schlüssel, prüft Aussteller und Nonce. Kein Umgehungsweg
gefunden.
1.2 Rate-Limiting/Account-Lockout im Mehrinstanz-Betrieb (Akzeptanzkriterium 2, Prüfung 1)
| Angriff | Test | Zielwert | Ergebnis |
|---|---|---|---|
| Rate-Limit über 4 unabhängige "Instanzen" (eigene DB-Pools) parallel umgehen | TestPentest_RateLimit_MultiInstanceBypassAttempt |
Gesamtsumme erlaubter Anfragen = konfiguriertes Limit, nicht mehr | bestanden – 200 Anfragen über 4 Instanzen, exakt 100 (=Limit) erlaubt |
| Account-Lockout über 3 unabhängige Instanzen verteilte Brute-Force-Versuche umgehen | TestPentest_Lockout_MultiInstanceBypassAttempt |
Konto wird trotz Verteilung gesperrt | bestanden – 12 Versuche über 3 Instanzen, Sperre nach Erreichen von maxFailed=5 |
Ergebnis: beide Mechanismen nutzen ein atomares SQL-UPSERT gegen
geteilten, externen Zustand (Postgres) statt In-Process-Zähler – exakt der
in archivdms als Fehlerklasse dokumentierte Schwachpunkt wird hier vermieden.
1.3 Zentrale Policy-Durchsetzung, gezielter Umgehungsversuch je Modul (Akzeptanzkriterium 3, Prüfung 3)
| Angriff | Test | Zielwert | Ergebnis |
|---|---|---|---|
Rechteausweitung: Rolle user/tenant_admin versucht platform.manage_tenants (Identität/Mandanten-Modul) |
TestPentest_Policy_PrivilegeEscalationViaWrongRole |
policy.ErrDenied |
bestanden |
Strukturelle Umgehung von policy.Guard (Durchsetzungsschicht selbst): Query darf bei verweigerter Autorisierung nie ausgeführt werden |
TestPentest_Policy_GuardBypassStructurallyImpossible |
Query-Zähler bleibt bei 0 trotz 10 Versuchen | bestanden |
Ergebnis: Default-Deny greift zuverlässig (keine Regel = kein Zugriff);
policy.Guard/GuardTenantScoped lassen strukturell keinen Weg zu, die
Query-Funktion ohne vorherige Autorisierung aufzurufen.
1.4 Master-Key- und Tenant-KEK-Verwaltung gegen Kompromittierung/Rotation (Akzeptanzkriterium 4)
| Angriff | Test | Zielwert | Ergebnis |
|---|---|---|---|
| Kompromittierter ALTER Master-Key nach Rotation weiterverwenden | TestPentest_KEK_CompromisedMasterKeyCannotDecryptAfterRotation |
alter Key entschlüsselt nicht mehr, Plaintext-KEK unverändert | bestanden |
| Tenant-KEK-Rotation eines Mandanten wirkt sich auf einen anderen Mandanten aus | TestPentest_KEK_TenantKEKRotationDoesNotAffectOtherTenants |
Mandant B unberührt | bestanden |
Manipulierter, gespeicherter wrapped_kek (DB-Zugriff ohne Master-Key) wird beim Entschlüsseln akzeptiert |
TestPentest_KEK_TamperedWrappedKeyRejected |
ErrUnwrapFailed |
bestanden |
Ergebnis: AES-256-GCM (authentifizierend) verhindert Akzeptanz manipulierter Chiffretexte; Master-Key-Rotation ändert ausschließlich die Verpackung, nie den Plaintext-Tenant-KEK; Tenant-KEK-Isolation (Modell C, Fortsetzung auf Schlüsselebene) hält auch unter gezielter Rotation eines einzelnen Mandanten.
2. Beim Merge/Pentest gefundene Fehler (nicht vorab bekannt)
2.1 scripts/reset-test-env.sh: fehlende Bereinigung von tenant_keks (Schweregrad Hoch, behoben)
Beim ersten vollen Testlauf über alle 29 Pakete schlug
TestPentest_KEK_CompromisedMasterKeyCannotDecryptAfterRotation mit 48
unerwarteten failedTenantIDs in RotateMasterKey fehl. Ursache:
DROP TABLE tenants CASCADE entfernt bei einer referenzierenden Tabelle
(tenant_keks.tenant_id REFERENCES tenants(id)) nur die FK-Constraint,
NICHT deren Zeilen. Da reset-test-env.sh tenant_keks (API-10-Migration
0006_tenant_keks.up.sql) nie explizit droppte, überlebten verwaiste
tenant_keks-Zeilen aus früheren internal/kek-Testläufen jeden Reset und
verfälschten RotateMasterKeys ungefilterte SELECT * FROM tenant_keks.
Behoben: reset-test-env.sh droppt jetzt explizit alle Registry-Tabellen aus
migrations/*.up.sql (tenant_keks, rate_limit_counters,
rate_limit_configs, policy_rule_changes, policy_rules,
feature_flags, module_credentials, modules), nicht nur die vier
ursprünglich behandelten. Reiner Testinfrastruktur-Fix, keine
Produktionsmigration verändert.
2.2 internal/e2e-Tests: defer adminPool.Close() lief vor t.Cleanup-Bereinigung (Schweregrad Mittel, behoben)
Voller Testlauf zeigte anschließend internal/migrate-Fehlschläge
(„erwartet 3 Ergebnisse, habe 15" bzw. 12, mit Zeilen wie e2e_tenant_a).
Ursache: TestE2E_TenantOnboardingLoginFlow und TestE2E_CrossTenantIsolation
schlossen den adminPool per defer adminPool.Close(), ihre
t.Cleanup-Funktion (welche die angelegten Testmandanten wieder löscht)
lief aber – wie in Go üblich – ERST NACH allen defer-Aufrufen der
Testfunktion, also gegen einen bereits geschlossenen Pool. Der Fehler wurde
durch _, _ = adminPool.Exec(...) verschluckt; die Zeilen blieben dauerhaft
in der geteilten tenants-Tabelle stehen und verfälschten
internal/migrates ungefilterte registry.List()-Abfrage im selben
Prozess/derselben Datenbank.
Behoben: adminPool.Close() in beiden Tests über t.Cleanup statt defer
registriert (vor der Lösch-Cleanup, sodass LIFO die richtige Reihenfolge
erzwingt – Pool bleibt bis nach dem Löschen offen).
2.3 internal/kek/kek_test.go: derselbe defer/t.Cleanup-Fehler, zusätzlich fehlende Zeilen-Bereinigung (Schweregrad Mittel, behoben)
Dieselbe Fehlerklasse wie 2.2, zusätzlich verschärft: createTenant legte
Zeilen mit db_dsn='unused' an, ohne JEMALS eine eigene Aufräumfunktion zu
registrieren – setupTests cleanup := func(){ pool.Close() } schloss nur
den Pool, löschte aber nie die angelegten tenants/tenant_keks-Zeilen.
Behoben: createTenant registriert jetzt eine eigene t.Cleanup, die
Zeile+abhängigen tenant_keks-Eintrag löscht; setupTest schließt den Pool
über t.Cleanup (nicht mehr über den zurückgegebenen cleanup(), den
Aufrufer per defer aufriefen) – damit läuft die Lösch-Cleanup (später
registriert) vor dem Pool-Schließen (früher registriert).
2.4 internal/migrate/migrate_test.go: hartkodiertes Testschema ohne Lifecycle-Spalten (Schweregrad Mittel, behoben)
setupOrchestratorTest legte tenants über ein eigenes,
hartkodiertes CREATE TABLE IF NOT EXISTS ohne die Spalten
previous_status/deletion_scheduled_at an, die TEN-04
(internal/tenant/registry.go, GetBySlug/List) inzwischen mitliest.
Lief das Paket ISOLIERT (Tabelle wird von diesem Test selbst frisch
angelegt), fiel der Fehler nicht auf; erst im vollen Testlauf – bei dem die
Tabelle bereits über die echten Registry-Migrationen existiert – griff
CREATE TABLE IF NOT EXISTS nicht mehr und der Fehler
column "previous_status" does not exist trat zutage.
Behoben: fehlende Spalten im Testschema ergänzt (kein Produktionscode betroffen).
3. Build/Test-Ergebnis auf 192.168.1.131 (/root/nexarch-code-qa04)
go mod tidy -> clean
go build ./... -> clean
go vet ./... -> clean
go test ./... -p 1 -count=1 -> 29/29 Pakete ok, 0 Fehlschläge
Enthält insbesondere internal/pentest (12 neue Angriffstests, alle
bestanden) sowie die bereits bestehenden 124 Tests aus QA-02/QA-03 und alle
Tests der 10 frisch gemergten Vorbedingungs-Branches.
4. Gesamtergebnis
Bestanden. Alle vier Akzeptanzkriterien durch gezielte, dokumentierte Angriffsversuche mit Ergebnisprotokoll erfüllt; alle drei Pflichtprüfungen durchgeführt und protokolliert (Abschnitte 1.2–1.4). Vier real gefundene Fehler (Abschnitt 2, Schweregrad Hoch/Mittel) behoben – ausschließlich Testinfrastruktur, kein Produktionscode verändert.