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 aanvalsoppervlak open te stellen).
open() is geen “pixel-ophaal-functie”
Image.open() werkt lazy. Het opent het bestand, identificeert het type en leest de pixeldata mogelijk nog niet. Het bestandshandle kan open blijven.
In beveiligings- 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/aantal pixels, 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 bestand dat
verify()doorstaat is niet automatisch veilig; problemen kunnen pas bijload()zichtbaar worden, 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-aanvalsvector: een klein bestand kan na decompressie enorm groot worden.
Pillow waarschuwt voor een decompressiebom en heeft standaardlimieten (bijv. 128 Mpx). Django gebruikt om 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 bedrijfsvalidaties, dan 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 een eerste blokkering te doen. - Gebruik
verify()om duidelijk corrupte bestanden te verwijderen. - Decodeer in een gecontroleerde omgeving en normaliseer naar standaard pixelformaten (RGB/RGBA).
- Herencodeer 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 pixellimieten 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/geheugengebruik (niet overmatig gebruiken in validatie).- Praktische oplossing: Vertrouw alleen op hergecodeerde bestanden (met limieten/isolatie).
Gerelateerde artikelen: