Skip to content

Onderzoek: veilig vector-SVG ondersteunen (nu gerasteriseerd naar WebP) #352

@robbertbos

Description

@robbertbos

Aanleiding

Bij de afbeelding-hardening (#343 / PR #347) blokkeert de backend nu het rechtstreeks opslaan van een rauwe data:image/svg+xml-databron; alleen raster-formaten (webp/png/jpeg/gif) worden geaccepteerd. Dit is bewust conservatief. SVG is voor diagrammen/architectuurplaatjes echter fijn (haarscherp bij elke zoom, klein, toegankelijk). Dit issue is om te onderzoeken of en hoe we echte vector-SVG veilig kunnen ondersteunen — met een expliciete onderbouwing waarom het nu niet aanstaat, én een eerlijke schets van de mogelijkheden om het wél te doen.

Huidige situatie (stand van zaken)

Waarom nu niet (onderbouwing standaarden / BIO)

SVG is geen statische afbeelding maar actieve content: het kan <script>, event-handlers (onload=), <foreignObject> en externe verwijzingen bevatten. Rauwe, niet-gesaneerde SVG die ergens inline in de DOM belandt, voert die code uit → stored XSS. Voor een overheids-DPIA-tool met gevoelige gegevens weegt dat zwaar:

  • BIO (Baseline Informatiebeveiliging Overheid) — verplicht normenkader (o.b.v. ISO 27002). Relevant: invoervalidatie en secure development (o.a. 8.26 application security requirements, 8.28 secure coding). Uploads moeten als onvertrouwd worden behandeld en gevalideerd/gesaneerd.
  • NCSC — ICT-beveiligingsrichtlijnen voor webapplicaties (sluit expliciet aan op de BIO; via Forum Standaardisatie verplicht voor overheidswebsites): invoervalidatie, content-handling en CSP. Treat uploads als untrusted.
  • NeRDS richtlijn 6 — Maak veilige systemen + de leidraad op developer.overheid.nl: secure-by-design en defense-in-depth. De huidige rasterisatie + server-allowlist is precies dat: de visuele waarde behouden, het risico weghalen.
  • OWASP: SVG-upload-XSS is een bekende klasse; het advies is SVG als actieve content te behandelen en óf te saneren, óf via <img> te renderen, óf te rasteriseren (PNG/WebP) — dat laatste verwijdert alle uitvoerbare inhoud en is wat we nu doen.

Kortom: de huidige keuze (rasteriseren) is verdedigbaar en standaard-conform. Het is een bewuste leg-uit: visueel resultaat behouden, aanvalsoppervlak elimineren.

Mogelijkheden om het wél (veilig) te doen

Er zijn reële opties die écht vector-SVG behouden — met oplopende complexiteit en restrisico:

  1. Gesaneerde inline-SVG (DOMPurify, server + client). Strip <script>, <foreignObject>, event-handlers en externe/javascript:-verwijzingen. Aandachtspunten: sanitizer-bypasses zijn voorgekomen (bv. CVE-2024-47875), dus ook XML-entity-expansie (billion-laughs) en grootte begrenzen; saneren op de server (niet alleen client), plus een strikte CSP. Onderhoudslast + audit nodig.
  2. Alleen via <img> renderen (geen inline-SVG). Browsers voeren géén scripts uit in SVG die via <img src=data:image/svg+xml> wordt geladen, en blokkeren externe resource-loads. ImageField.vue toont al via <img :src>. Relatief veilig voor weergave, maar fragiele garantie: de PDF-export (pdfmake) behandelt SVG anders dan raster, en elk toekomstig inline-gebruik doorbreekt de aanname.
  3. Server-side rasteriseren naar PNG/WebP (bv. resvg/sharp), evt. op hogere resolutie. Consistente output, strikt zonder actieve content — maar nog steeds raster (geen vector). Verbetert hooguit de scherpte t.o.v. nu.

Opties 1 en 2 leveren echte vector op; 3 niet. Voor weergave-kwaliteit zonder vector kan ook simpelweg de huidige rasterisatie op hogere resolutie/instelbaar gemaakt worden.

Tegenargument (pro-SVG, voor de balans)

  • Toegankelijkheid (WCAG / NeRDS toegankelijkheid): SVG schaalt zonder kwaliteitsverlies en kan <title>/tekst bevatten — gunstig voor zoom en screenreaders.
  • Kwaliteit & omvang: voor diagrammen vaak scherper én kleiner dan raster.

Te onderzoeken / acceptatiecriteria

  • Concrete dreigingsanalyse voor onze sinks: <img>-weergave, PDF-export (pdfmake), en eventuele toekomstige inline-rendering.
  • Haalbaarheid + onderhoudslast van server-side SVG-sanitisatie (DOMPurify in Node, of een los proces), incl. entity-expansie- en groottelimieten.
  • CSP-impact en of img-src data: voldoende is, of dat een aparte aanpak nodig is.
  • Afhandeling in de PDF-export (pdfmake svg-node vs. raster).
  • Expliciet BIO/NCSC-akkoord (pas-toe-of-leg-uit) bij de gekozen richting.
  • Go/no-go: óf veilige vector-SVG implementeren, óf de leg-uit (rasterisatie) documenteren — eventueel met hogere-resolutie-rasterisatie als compromis.

Referenties

Context: server-side blokkade geïntroduceerd in #343 / PR #347.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions