Pentest R93: Leerer String != fehlender Query-Param
R93.1 INFO: ?accountId= (explizit-leer) wurde wie ?accountId weggelassen behandelt → 200 statt 400 auf optionalen Endpunkten. Pentester-Spec: leerer String ist keine gültige Zahl. Fix in parsePositiveIntQuery: nur `v === undefined` ist absent; '', ' ', alles andere muss parsen. Required + optional Modes unverändert. Sanity-Test: alle 11 Cases grün. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -64,8 +64,13 @@ function parsePositiveIntQuery(
|
|||||||
res: Response,
|
res: Response,
|
||||||
options?: { required?: boolean },
|
options?: { required?: boolean },
|
||||||
): number | undefined | null {
|
): number | undefined | null {
|
||||||
const absent = v === undefined || v === '' || (typeof v === 'string' && v.trim() === '');
|
// Pentest 93.1 (INFO, 2026-06-21): `?accountId=` (explizit-leer) wurde
|
||||||
if (absent) {
|
// wie `?accountId` weggelassen behandelt → 200 statt 400 auf optionalen
|
||||||
|
// Endpunkten. Spec sagt aber: leerer String ist KEINE gültige Zahl.
|
||||||
|
// Trennung jetzt strikt:
|
||||||
|
// - Param fehlt komplett (`undefined`) → "absent"
|
||||||
|
// - Param da, aber Wert leer/Whitespace/keine Zahl → invalid → 400
|
||||||
|
if (v === undefined) {
|
||||||
if (options?.required) {
|
if (options?.required) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -82,7 +87,15 @@ function parsePositiveIntQuery(
|
|||||||
} as ApiResponse);
|
} as ApiResponse);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const n = parseInt(v, 10);
|
const trimmed = v.trim();
|
||||||
|
if (trimmed === '') {
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: `${fieldLabel} darf nicht leer sein – bitte weglassen oder positive Ganzzahl angeben.`,
|
||||||
|
} as ApiResponse);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const n = parseInt(trimmed, 10);
|
||||||
if (!Number.isFinite(n) || n < 1 || !Number.isInteger(n)) {
|
if (!Number.isFinite(n) || n < 1 || !Number.isInteger(n)) {
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
|
|||||||
@@ -97,6 +97,16 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
|||||||
|
|
||||||
## ✅ Erledigt
|
## ✅ Erledigt
|
||||||
|
|
||||||
|
- [x] **🔒 Pentest R93 – Leerer String != fehlender Param**
|
||||||
|
- R93.1 (INFO): `?accountId=` (explizit-leer) wurde wie `?accountId`
|
||||||
|
weggelassen behandelt → 200 statt 400 auf optionalen Endpunkten.
|
||||||
|
Pentester-Spec: leerer String ist KEINE gültige Zahl.
|
||||||
|
- Fix im `parsePositiveIntQuery()`-Helper: striktere Absent-Logik
|
||||||
|
(`v === undefined` ist absent; `''`, `' '`, alles andere muss
|
||||||
|
parsen). Required + optional Modes unverändert.
|
||||||
|
- Float-Grenzfall (`accountId=5.5` → 5 via `parseInt`) bleibt als
|
||||||
|
by-design akzeptiert (Pentester-Bestätigung, kein Security-Impact).
|
||||||
|
|
||||||
- [x] **🔒 Pentest R92 – Strict-400 für accountId auf Vertrags-Endpunkten**
|
- [x] **🔒 Pentest R92 – Strict-400 für accountId auf Vertrags-Endpunkten**
|
||||||
- R91-Fix war silent-undefined bei invaliden Werten: `accountId=abc`
|
- R91-Fix war silent-undefined bei invaliden Werten: `accountId=abc`
|
||||||
auf `GET /contracts/:id/emails` ergab "kein Filter" → Mailbox-
|
auf `GET /contracts/:id/emails` ergab "kein Filter" → Mailbox-
|
||||||
|
|||||||
Reference in New Issue
Block a user