Pentest R86: Vertrags-Identifier max 100 + Charset-Whitelist

R86.1 LOW + R86.2 LOW: >999-Zeichen liefen in DB-Overflow (500
statt 400), Attribut-Injection (`foo" onerror=…` ohne
umschließenden Tag) überlebte stripHtml.

Fix: validateContractIdentifier() (max 100,
^[A-Za-z0-9_\-/. ]{0,100}$) in sanitize.ts, eingehängt in
sanitizeContractBody. Wirft ApiError(400, …). Literales Space
statt \s → kein CRLF/Tab → kein Header-Injection-Vektor in
CSV-/Mail-/PDF-Export. Greift auf alle fünf Identifier-Felder
(Provider + Sales-Platform). ContractForm-Inputs bekommen
maxLength={100} als UX-Schicht.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:14:00 +02:00
parent 0b7bb89ebc
commit c8b86ca9a7
5 changed files with 115 additions and 7 deletions
@@ -956,11 +956,11 @@ export default function ContractForm() {
options={availableTariffs.map((t) => ({ value: t.id, label: t.name }))}
disabled={!selectedProviderId}
/>
<Input label="Kundennummer beim Anbieter" {...register('customerNumberAtProvider')} />
<Input label="Vertragsnummer beim Anbieter" {...register('contractNumberAtProvider')} />
<Input label="Auftragsnummer bei Vertriebsplattform" {...register('orderNumberAtSalesPlatform')} />
<Input label="Kundennummer bei Vertriebsplattform" {...register('customerNumberAtSalesPlatform')} />
<Input label="Vertragsnummer bei Vertriebsplattform" {...register('contractNumberAtSalesPlatform')} />
<Input label="Kundennummer beim Anbieter" maxLength={100} {...register('customerNumberAtProvider')} />
<Input label="Vertragsnummer beim Anbieter" maxLength={100} {...register('contractNumberAtProvider')} />
<Input label="Auftragsnummer bei Vertriebsplattform" maxLength={100} {...register('orderNumberAtSalesPlatform')} />
<Input label="Kundennummer bei Vertriebsplattform" maxLength={100} {...register('customerNumberAtSalesPlatform')} />
<Input label="Vertragsnummer bei Vertriebsplattform" maxLength={100} {...register('contractNumberAtSalesPlatform')} />
<Input label="Provision (€)" type="number" step="0.01" {...register('commission')} />
<Input label="Preis erste 12 Monate" {...register('priceFirst12Months')} placeholder="z.B. 29,99 €/Monat" />
<Input label="Preis ab 13. Monat" {...register('priceFrom13Months')} placeholder="z.B. 39,99 €/Monat" />