Beveiligingsperspectief op Pillow’s open(), verify() en load()
Afbeeldingen uploaden is niet simpelweg “een bestand ontvangen”; het is het doorgeven van externe input aan een decoder (parser). De drie Pillow‑methoden gaan dus niet alleen over hun functionaliteit, maar vooral over wanneer ze worden aangeroepen (en zo het aanvalssurface open te stellen).
open() is geen “pixel‑ophaal‑functie”
Image.open() werkt lazy. Het opent het bestand, identificeert het type en kan de pixel‑data nog niet lezen. Het bestandshandle kan open blijven.
In beveiliging en operationele omgevingen is het gebruik van open() eenvoudig:
- Gebruik
open()om het formaat, de breedte/hoogte en andere lichte informatie te verkrijgen. - Blokkeer via beleid: toegestane formaten, maximale resolutie/beeldpunten, uploadlimiet.
- Ga vervolgens naar de volgende stap (verificatie/decodering).
Kortom, open() is een tool om beslissingsinformatie vóór decodering te extraheren.
Wat garandeert verify() en wat niet?
verify() probeert te bepalen of het bestand corrupt is, maar decodeert de daadwerkelijke afbeelding niet. Bij een fout wordt een uitzondering gegooid; om het bestand daarna nog te gebruiken, moet je het opnieuw openen.
Conclusies vanuit een beveiligingsperspectief:
- Voordeel: Je kunt snel corrupte bestanden uitsluiten zonder zware decodering.
- Beperking: Een door
verify()goedgekeurd bestand is niet veilig; het kan nog steeds problemen veroorzaken bijload()omdat de volledige decodering nog niet is uitgevoerd.
load() is gevaarlijk als het onzorgvuldig wordt aangeroepen
load() voert de daadwerkelijke decodering (inclusief decompressie) uit en laadt de pixels in het geheugen. Dit is een directe DoS‑aanvalvector: een klein bestand kan na decompressie enorm groot worden.
Pillow waarschuwt voor “decompressie‑boom” en heeft standaard limieten (bijv. 128 Mpx). Django gebruikt in dezelfde reden verify() in plaats van load() bij het valideren van afbeelding‑uploads. In de broncode staat een commentaar: “load() laadt het volledige beeld in het geheugen en vormt een DoS‑vector”.
Bij gebruik van Django/DRF: ImageField en verify() kunnen dubbel zijn
Django’s ImageField voert intern Image.open() + verify() uit. DRF’s serializers.ImageField roept dezelfde Django‑validatie aan.
Daarom:
- Als je al
serializers.ImageFieldgebruikt, is het meestal onnodig om invalidate()nogmaalsverify()aan te roepen. - Wil je extra beveiligings‑ of bedrijfs‑validaties, kun je beter een
FileFieldgebruiken en je eigen validatie‑pipeline opzetten.
Hoe garandeer je “veiligheid” voor geüploade bestanden?

De meest realistische aanpak is:
- Gebruik
open()om lichte informatie te lezen en eerste blokkering te doen. - Gebruik
verify()om duidelijk corrupte bestanden te verwijderen. - Decodeer in een gecontroleerde omgeving en normaliseer naar standaard pixelformaten (RGB/RGBA).
- Herencode het resultaat in een door de server gekozen formaat.
- Sla en serveer alleen het hergecodeerde bestand.
Deze strategie geeft de server controle over de uiteindelijke output, waardoor onnodige metadata en vreemde structuren worden verwijderd. Let op: herencoding vereist nog steeds load(), dus stel vooraf geheugen‑ en pixel‑limieten in en voer het in een geïsoleerde worker of proces uit.
Samenvatting
open(): Identificatie + lichte informatie (pixels nog niet geladen).verify(): Eerste filter op corruptie (zonder decodering, opnieuw openen nodig voor gebruik).load(): Start van decodering/memory‑gebruik (niet overmatig gebruiken in validatie).- Praktische oplossing: Vertrouw alleen op hergecodeerde bestanden (met limieten/isolatie).
Gerelateerde artikelen: