fix(cert-manager): Reiter zeigen nur noch passende Auswertungen, Aufteilen schützt Schlüssel
- Ausgabe-Reiter bieten nur an, was zur aktuellen Dateiliste passt: nach dem Entfernen einer Datei oder einer fehlgeschlagenen Prüfung kommt Hinweis oder Fehler mit „Erneut versuchen“ statt der alten Auswertung (WR-02) - Aufteilen: ein in der Datei geschützter Schlüssel bleibt geschützt (Passwort für die Ausgabe, auch in der ZIP); ohne Schutz nur ausdrücklich und mit sichtbarem Hinweis; Schlüssel heißen nach ihrem Zertifikat (WR-03, IN-05) - Meldungen: tooManyItems, aiaNotAllowed, buildFailed (statt „Dateien konnten nicht geprüft werden“ beim Erstellen), protectionTooExpensive; Hinweis zum Passwort genauer (IN-03, IN-05) - Download-Adresse wird erst nach einer Sekunde widerrufen (IN-04) - Anleitungen und Änderungsliste: Grenzen, Aufteilen mit Schlüsselschutz, Umlaut-Passwörter Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -909,22 +909,49 @@ deshalb für die Dauer **eines** synchronen Aufrufs drei Funktionen von `forge.p
|
||||
(`privateKeyToAsn1`, `wrapRsaPrivateKey`, `certificateToAsn1`) gegen Durchreicher aus und stellt
|
||||
sie im `finally` wieder her; ASN.1 für Zertifikate und Schlüssel kommt aus `node:crypto`, die
|
||||
Verschlüsselung und den MAC macht weiterhin forge. Das ist sicher, weil Node einfädig ist und der
|
||||
Aufruf nicht abgibt; das Spec prüft die Wiederherstellung auch nach einem Fehler. Profile:
|
||||
Aufruf nicht abgibt; das Spec prüft die Wiederherstellung auch nach einem Fehler. **Passwörter:**
|
||||
forge leitet den AES-Schlüssel (PBES2/PBKDF2) aus einem Byte je UTF-16-Einheit ab, OpenSSL 3, Windows
|
||||
und Java nehmen die UTF-8-Bytes; mit Umlaut oder `€` wäre ein „modernes“ PFX sonst für jedes andere
|
||||
Programm unlesbar (und umgekehrt, Review CR-03). Darum ersetzt `withForgeKdf` (Lesen **und**
|
||||
Schreiben) zusätzlich `forge.pkcs5.pbkdf2` durch eine Ableitung mit `node:crypto` aus den UTF-8-Bytes
|
||||
(auch SHA-256/512 nativ statt in reinem JavaScript). Die PKCS#12-eigene Ableitung (3DES, RC2, MAC)
|
||||
bleibt, wie sie ist: sie nimmt BMPString (UTF-16) aus den Zeichen, genau wie OpenSSL. Dieselbe
|
||||
Stelle zählt die Ableitungsrunden (siehe „Grenzen je Anfrage“). Profile:
|
||||
`compat` (3DES, SHA-1, Vorgabe, lesbar bis Windows Server 2016) und `modern` (AES-256, der MAC bleibt
|
||||
bei forge SHA-1). Die Vorlagen für IIS und Tomcat nutzen dieselbe Funktion (`cert-templates.ts`);
|
||||
die Vorlagen für Dateien bauen aus denselben Bausteinen wie `buildOutput` und kennen `cert-output.ts`
|
||||
bewusst nicht (sonst entstünde eine Importschleife).
|
||||
|
||||
*ZIP-Grenzen.* `zip-expand.ts` prüft **alles vor dem ersten Entpacken** an den Kopfdaten: höchstens
|
||||
100 Einträge, 1 MiB je Eintrag, Verhältnis entpackt zu gepackt höchstens 100, Summe 20 MiB, nur eine
|
||||
Ebene (ein ZIP im ZIP wird gemeldet, nicht geöffnet), verschlüsselte Einträge werden gemeldet.
|
||||
Eintragsnamen dienen nur der Anzeige und werden nie als Dateipfad benutzt.
|
||||
*ZIP-Grenzen.* `zip-expand.ts`: höchstens 100 Einträge, 1 MiB je Eintrag, Verhältnis entpackt zu
|
||||
gepackt höchstens 100, Summe 20 MiB, nur eine Ebene (ein ZIP im ZIP wird gemeldet, nicht geöffnet),
|
||||
verschlüsselte Einträge werden gemeldet. Die Kopfdaten (deklarierte Größe im Zentralverzeichnis)
|
||||
sind nur Angreiferwunsch: adm-zip begrenzt die Ausgabe bei deklarierter Größe 0 gar nicht, ein
|
||||
300-kB-ZIP entpackte dort zu 300 MiB (Review CR-01). Darum entpackt das Modul selbst
|
||||
(`inflateRawSync` mit `maxOutputLength` = Einzelgrenze, höchstens die Restgrenze der Summe) und prüft
|
||||
Größe, Verhältnis und CRC am echten Ergebnis; weicht die echte Größe von der deklarierten ab, gilt der
|
||||
Eintrag als `suspicious`. Eintragsnamen dienen nur der Anzeige und werden nie als Dateipfad benutzt.
|
||||
|
||||
*Grenzen je Anfrage.* `cert-budget.ts` (`RequestBudget`, in `analyzeWorkingSet` einmal je Anfrage
|
||||
angelegt und über `DetectContext.budget` durch alle Stufen gereicht): höchstens 200 Zertifikate, 50
|
||||
Schlüssel, 50 Zertifikatsanfragen (413 `tooManyItems`; der Kettenbau ist quadratisch). Der Aufwand des
|
||||
Passwortschutzes ist begrenzt (Review WR-04): eine Ableitung höchstens 1 000 000 Runden, alle zusammen
|
||||
höchstens 6 000 000 je Anfrage; Runden werden vor dem Rechnen gemeldet (PKCS#12 über die drei
|
||||
Ableitungsfunktionen von forge, verschlüsseltes PKCS#8 über `pkcs8Iterations` aus den Parametern),
|
||||
zu teuer ergibt `protectionTooExpensive` für diese Datei. Der PEM-Scanner `pem-scan.ts` ist linear
|
||||
(Review CR-02): die alte Regex `BEGIN … END` war bei vielen BEGIN-Zeilen ohne END quadratisch und
|
||||
blockierte die API (5 MiB: Minuten); der Scanner sammelt die END-Stellen je Etikett in einem
|
||||
Durchlauf und begrenzt die Blöcke auf 1000 je Text. Stellen, die Lesefehler bewusst verschlucken,
|
||||
reichen die Anfragegrenzen mit `rethrowRequestError` weiter. Beim Empfang zählt
|
||||
`cert-upload.ts` (eigener multer-Speicher) die Summe mit und bricht bei 20 MiB mit 413 `tooLarge` ab,
|
||||
statt erst nach 30 vollständig gepufferten Dateien (Review WR-06). Die HTTP-Einrichtung
|
||||
(`http-setup.ts`, aus `main.ts`) hängt den `build`-Leser **hinter** `enableCors` ein, damit auch
|
||||
seine 413/400-Antworten CORS-Kopfzeilen tragen (Review WR-01; das Spec prüft die Reihenfolge).
|
||||
|
||||
*Grenze des Anfragekörpers von `build` (D-26).* Die Express-Voreinstellung von 100 kB reicht für die
|
||||
größte erlaubte `build`-Anfrage nicht (Zertifikat, 20 Pool-Zertifikate, Schlüssel und Anfrage zu je
|
||||
16 384 Zeichen ergeben rund 384 kB). Deshalb hat nur diese Route einen eigenen JSON-Leser mit
|
||||
512 KiB (`cert-json-body.ts`), den `main.ts` per `app.use(CERT_BUILD_ROUTE, certBuildJsonBody,
|
||||
certBuildBodyErrors)` **vor** `app.listen` einhängt (Nest registriert seine eigenen Leser erst in
|
||||
512 KiB (`cert-json-body.ts`), den `configureHttp` in `http-setup.ts` per `app.use(CERT_BUILD_ROUTE,
|
||||
certBuildJsonBody, certBuildBodyErrors)` nach `enableCors` und **vor** `app.listen` einhängt (Nest registriert seine eigenen Leser erst in
|
||||
`init()`). Zwei Fallen: Erstens liegt `express` nicht in `apps/api/node_modules`, der Leser kommt
|
||||
deshalb über `createRequire(...)` aus der Kopie, die auch `@nestjs/platform-express` lädt. Zweitens
|
||||
**darf die Funktion nicht `jsonParser` heißen**: Nests `ExpressAdapter` überspringt seinen eigenen
|
||||
|
||||
Reference in New Issue
Block a user