Pentest 68.1 (LOW) + 68.2 (INFO): PDF-Active-Content-Filter + Modal-Limit
68.1: Magic-Byte-Check prüfte nur %PDF-. PDFs mit /JavaScript, /JS, /Launch, /EmbeddedFile, /RichMedia (Flash) kamen durch und wurden inline ausgeliefert – Browser-Viewer ignorieren JS, Adobe Acrobat nicht. - Neuer Helper assertSafePdf(buf) in utils/sanitize.ts mit case-sensitivem String-Scan auf die fünf Action-Patterns (\b-Word-Boundary verhindert False-Positives bei /JSXForm etc.). - Neue Middleware pdfUploadSafety.ts mit zwei Varianten: requireSafeUploadedPdf (PDF-only) und scanUploadedPdfIfPresent (durchwinkt JPG/PNG, scannt nur PDFs). - Eingehängt in: upload.routes (Magic-Byte-Validator erweitert), gdpr.routes Vollmacht-Upload, pdfTemplate.routes Template-Upload, contract.routes Vertragsdokumente, cachedEmail.controller (saveAttachmentTo, saveAttachmentAsInvoice, saveAttachmentAsContractDocument). - Inline-Vorschau bleibt – Pentester-Empfehlung "disposition=inline abschalten" wurde bewusst nicht umgesetzt (löst Acrobat-Risiko nicht, bricht aber ~20 UI-Stellen). - Smoke-Test: 5 Payload-Typen abgelehnt, clean PDF + Non-PDF + JSXForm durchgewinkt. 68.2: JpgToPdfModal-Self-DoS – MAX_IMAGES=50, MAX_IMAGE_BYTES=25MB.
This commit is contained in:
@@ -31,6 +31,12 @@ interface JpgToPdfModalProps {
|
||||
fileNameHint?: string;
|
||||
}
|
||||
|
||||
// Pentest 68.2 (INFO): Self-DoS-Schutz – Modal kann sonst den Tab des
|
||||
// Uploaders selbst zum Absturz bringen. Werte konservativ gewählt:
|
||||
// 50 Bilder × 25 MB = 1.25 GB ist mehr als jede legitime Vollmacht.
|
||||
const MAX_IMAGES = 50;
|
||||
const MAX_IMAGE_BYTES = 25 * 1024 * 1024;
|
||||
|
||||
function makeId() {
|
||||
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
||||
}
|
||||
@@ -107,6 +113,15 @@ export default function JpgToPdfModal({
|
||||
setError(null);
|
||||
const added: ImageItem[] = [];
|
||||
for (const file of list) {
|
||||
// 68.2: Self-DoS-Schutz – harte Schranken pro Bild und gesamt.
|
||||
if (file.size > MAX_IMAGE_BYTES) {
|
||||
setError(`Bild zu groß (max. ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)} MB): ${file.name || 'unbenannt'}`);
|
||||
continue;
|
||||
}
|
||||
if (images.length + added.length >= MAX_IMAGES) {
|
||||
setError(`Maximal ${MAX_IMAGES} Bilder pro PDF erlaubt.`);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
const dataUrl = await readFileAsDataUrl(file);
|
||||
const img = await loadImage(dataUrl);
|
||||
@@ -127,7 +142,7 @@ export default function JpgToPdfModal({
|
||||
if (added.length > 0) {
|
||||
setImages((prev) => [...prev, ...added]);
|
||||
}
|
||||
}, []);
|
||||
}, [images.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
|
||||
Reference in New Issue
Block a user