Comment reconnaître le type réel d'un fichier grâce aux magic bytes
Le défi
Un utilisateur a envoyé ceci en tant que 'avatar.png'. Un vrai PNG doit commencer par la signature 89 50 4E 47. Lisez les premiers octets du fichier et identifiez son vrai type.
Ce que tu vas apprendre
- Comprendre ce que sont les magic bytes (la signature d'un fichier) et où ils se situent dans le fichier
- Lire un hex dump avec sa colonne ASCII pour reconnaître le format réel d'un fichier
- Expliquer pourquoi le nom d'un fichier et son Content-Type déclaré ne prouvent rien sur son contenu
- Reconnaître comment les attaquants déguisent un type de fichier en un autre pour contourner les contrôles d'extension
- Décrire comment la validation de signature côté serveur renforce un pipeline d'upload de fichiers
Compétences testées
Prérequis
- À l'aise avec la lecture de l'hexadécimal et de l'ASCII de base
- Savoir qu'un fichier a une structure binaire propre, pas seulement une extension
Comment ça marche
Presque tous les formats de fichier commencent par une courte séquence d'octets fixe, appelée nombre magique ou signature de fichier. Les programmes lisent ces premiers octets pour déterminer ce qu'est réellement un fichier avant d'en faire quoi que ce soit. Une image PNG, par exemple, commence toujours par 89 50 4E 47 (les octets épellent .PNG dans la colonne ASCII), un JPEG commence par FF D8 FF, un PDF commence par 25 50 44 46 (%PDF), et une archive ZIP commence par 50 4B 03 04 (PK..). La signature se trouve tout au début du fichier et ne change pas simplement parce que quelqu'un renomme le fichier ou définit un en-tête Content-Type différent.
C'est tout l'enjeu de ce défi : l'upload est nommé avatar.png, mais un nom n'est qu'une étiquette choisie par l'utilisateur. La vérité est dans les octets. Ouvrir le fichier dans une vue hexadécimale affiche deux colonnes : l'hexadécimal brut à gauche et une colonne ASCII imprimable à droite. Quand les premiers octets ne correspondent pas à la signature promise par l'extension, le fichier n'est pas ce qu'il prétend être. La colonne ASCII est votre raccourci : de nombreuses signatures sont du texte lisible, donc un coup d'œil rapide révèle souvent le vrai format plus vite que de mémoriser l'hexadécimal.
C'est important car le type de fichier est une frontière de sécurité. Un pipeline d'images s'attend à décoder des pixels ; si on lui fournit à la place un exécutable, un script ou une archive, les hypothèses s'effondrent, et un attaquant capable de faire passer le mauvais type par un contrôle faible obtient un point d'entrée. Lire les magic bytes est la compétence forensique qui comble cette faille.
Erreurs fréquentes
- Faire confiance à l'extension du fichier. Une terminaison
.pngn'est qu'un texte dans le nom du fichier ; n'importe qui peut renommer n'importe quoi. L'extension est un indice, jamais une preuve. - Faire confiance à l'en-tête Content-Type. C'est le navigateur ou le client qui le définit, et un client est entièrement sous le contrôle de l'attaquant.
image/pngdans une requête ne dit rien sur les octets réels. - Lire uniquement l'hexadécimal en ignorant la colonne ASCII. De nombreuses signatures épellent des lettres reconnaissables dans la colonne de droite ; l'ignorer vous complique inutilement la tâche.
- Supposer qu'un début d'apparence valide signifie que tout le fichier est sûr. Des magic bytes correspondants confirment le format, mais ne garantissent pas que le reste du fichier est inoffensif ou bien formé.
Comment s'en protéger
Lorsque vous acceptez des uploads de fichiers, ne déterminez jamais le type d'un fichier à partir de son nom ou de son en-tête Content-Type. Lisez les premiers octets réels côté serveur et vérifiez-les par rapport à la signature du format attendu, puis appliquez une liste blanche des types autorisés plutôt qu'une liste noire des types interdits.
Ajoutez des couches de défense supplémentaires pour qu'un fichier même correctement typé ne puisse pas nuire :
- Réencodez ou traitez les images acceptées via une bibliothèque de confiance, qui rejette les entrées malformées ou déguisées.
- Stockez les uploads en dehors de la racine web et servez-les depuis un domaine séparé avec un
Content-Dispositionforcé, afin qu'ils ne soient jamais exécutés ni interprétés sur votre origine. - Générez vos propres noms de fichiers aléatoires et ignorez entièrement le nom fourni par l'utilisateur.
- Limitez la taille des fichiers et validez les dimensions avant tout traitement lourd.