Sécurisation WordPress : sécuriser le upload des médias

Sur WordPress, l’upload de médias paraît banal. Pourtant, c’est souvent l’une des portes d’entrée les plus pratiques pour un attaquant. Entre un formulaire d’ajout dans l’admin, l’API REST, les plugins qui manipulent des fichiers, et les intégrations qui “importent” des images, le parcours du fichier est rarement aussi simple qu’on l’imagine.

La plupart des incidents ne viennent pas d’un “grand piratage” spectaculaire. Ils viennent plutôt de détails: un type de fichier accepté trop large, une validation côté serveur absente, une configuration de permissions trop ouverte, ou un plugin qui transforme une image en PHP accessible depuis le web. Quand on parle de sécurisation WordPress, sécuriser l’upload des médias, c’est consolider toutes les étapes, du moment où le fichier est pris en charge jusqu’à l’endroit où il est stocké et servi.

Pourquoi l’upload est un point sensible

Un fichier n’est pas “juste une image”. C’est un flux binaire. Et même si l’interface affiche “PNG”, ce que le serveur reçoit peut être différent, volontairement ou non. Les attaques exploitent plusieurs failles classiques.

D’abord, la vérification basée uniquement sur l’extension. Si un système se fie à “.jpg” pour croire que tout est bon, un contenu malicieux peut s’y cacher. Ensuite, la vérification basée sur le MIME déclaré par le navigateur, qui n’est pas une preuve. Une requête peut annoncer “image/jpeg” tout en transportant autre chose.

Il y a aussi les cas où le serveur traite différemment certains fichiers selon des règles de configuration Apache ou Nginx. Si vous autorisez trop d’extensions à être exécutées côté serveur, vous donnez de la valeur à un attaquant. Parfois, le fichier ne doit même pas être exécuté pour créer des dégâts: un fichier énorme peut saturer la mémoire et provoquer des blocages, ou un contenu non désiré peut polluer votre site.

Enfin, il y a la “zone d’ombre” des plugins. Beaucoup d’outils gèrent des imports, des galeries, des builders, des indexations, des redimensionnements, des webhooks. Dès qu’un plugin ajoute sa propre chaîne de traitement, la sécurité dépend aussi de ses choix, de son maintien, et de ses garde-fous.

Comprendre le chemin du fichier dans WordPress

Avant de verrouiller, il aide à visualiser le parcours réel:

Le navigateur envoie le fichier via un formulaire d’upload (dans l’interface d’admin ou une API). WordPress reçoit la requête et vérifie certaines limites. WordPress écrit le fichier dans le dossier prévu (souvent wp-content/uploads/). Selon la configuration serveur, certaines extensions peuvent être servies différemment. Le fichier est ensuite accessible via une URL.

Même si WordPress fait déjà des choses utiles, la sécurité globale dépend du contexte. Le serveur peut refuser des tailles, mais peut aussi être configuré de manière permissive. WordPress peut limiter certains types, mais un plugin peut réintroduire des chemins inattendus. Et si vous avez activé des fonctionnalités d’accessibilité (ex: conversions automatiques, imports distants, redimensionnement), ces fonctions peuvent déclencher des traitements côté PHP ou via des outils externes comme ImageMagick.

Ce sont ces points de bascule que vous voulez rendre “stricts” et “cohérents”.

image

Verrouiller ce que l’on autorise vraiment à uploader

La première mesure solide consiste à réduire la surface d’attaque. L’objectif n’est pas de rendre WordPress “parfait”, mais de rendre l’upload utile uniquement pour les médias nécessaires à votre activité.

Dans les configurations courantes, WordPress accepte une gamme de types d’images. Mais selon votre stack, vous pouvez vouloir ajouter du PDF (pour des documents), des SVG (pour des icônes), ou d’autres formats. Chaque ajout est une nouvelle surface.

Le piège est double: d’un côté, garder “trop large” pour éviter de bloquer des utilisateurs; de l’autre, ajouter un type “pratique” sans comprendre comment il sera servi par le serveur et interprété par les navigateurs.

Pour les images classiques, l’approche la plus robuste est de limiter aux formats qui ont une représentation claire et qui sont généralement traités comme des médias statiques: JPEG, PNG, WebP, GIF (avec prudence), éventuellement AVIF selon votre environnement. Pour les formats plus risqués, vous devez assumer les risques ou mettre en place un traitement strict.

Le cas des SVG illustre bien la nuance. Un SVG est du texte, donc manipulable. Un attaquant peut y cacher des scripts ou des références externes, selon les règles de parsing et la manière dont le serveur les sert. La “bonne” pratique n’est pas d’interdire systématiquement, mais de ne jamais considérer un SVG comme un simple fichier image sans nettoyage ou sandbox. Si vous n’avez pas une bonne raison d’en autoriser l’upload, le meilleur garde-fou reste de le refuser.

Validation serveur, pas seulement “côté interface”

Une erreur fréquente consiste à compter sur l’interface d’upload ou sur les validations JavaScript. Or, tout ce qui tourne dans le navigateur est modifiable. La validation utile, c’est celle qui se fait côté serveur au moment de la réception et avant l’écriture du fichier final.

WordPress effectue déjà des vérifications, mais selon votre configuration et vos ajouts, il peut être utile de renforcer la validation. Le niveau de détail dépend de votre environnement. Par exemple, vérifier que le contenu correspond réellement au format attendu (signature, cohérence des métadonnées, dimensions d’image) est plus fiable que se baser sur l’extension.

Dans mes audits, c’est souvent là que la différence se joue: un site accepte “image/png” via extension, et un autre accepte “image/png” seulement quand l’analyse du contenu montre une image cohérente. On n’a pas besoin d’être paranoïaque sur tous les octets, mais on doit refuser les cas manifestement incohérents.

Configuration serveur: éviter l’exécution de ce qui ne devrait pas l’être

Même avec une validation WordPress, votre serveur doit être configuré pour ne pas exécuter de code à partir des dossiers d’uploads. C’est une règle fondamentale: les médias ne devraient pas être interprétés comme du PHP.

Sur Apache, Nginx, ou via des réglages managés, l’objectif est similaire: empêcher l’exécution dans wp-content/uploads/ (et, par extension, dans les sous-dossiers où WordPress écrit ses fichiers). Cela peut se faire via des directives de type “désactiver handlers” ou “refuser l’interprétation” selon votre configuration. Sur des hébergements mutualisés, vous n’aurez pas forcément la main, mais vous pouvez souvent vérifier le comportement via un test en environnement de préproduction.

L’important est de comprendre le modèle de risque: si un attaquant parvient à faire upload un fichier avec une extension interprétable, vous voulez que le serveur le serve comme un flux statique, pas comme une application.

Gestion des permissions et des emplacements

Les permissions de fichiers et de dossiers comptent. Si votre dossier d’uploads est trop permissif, vous augmentez les chances d’un scénario dégradé. Et si des écritures partagées existent entre utilisateurs système, un dysfonctionnement peut devenir une opportunité.

Quelques principes pratiques, faciles à vérifier:

    wp-content/uploads doit être écrivable par le compte qui exécute PHP, pas par tout le monde. Les permissions ne doivent pas être “ouvertes par réflexe” lors de migrations. Les fichiers téléchargés ne devraient pas devenir des points de stockage “à tout faire”.

La bonne pratique est de s’aligner sur les recommandations de votre hébergeur et de votre mode d’exécution (PHP-FPM, mode module, conteneur, etc.). Si vous êtes en environnement managé, vous gagnerez du temps en demandant comment l’équipe gère les permissions plutôt que de modifier au hasard.

Tailles et ressources: empêcher les uploads qui mettent le site à genoux

Un attaquant n’a pas besoin de déposer un fichier malicieux pour causer des dommages. Un upload massif, répété, peut déclencher une saturation de ressources. Même sans malveillance, des utilisateurs peuvent téléverser des images trop lourdes, ou des fichiers que votre serveur redimensionne ensuite avec des traitements coûteux.

Les paramètres clés dépendent de votre configuration. Côté PHP, vous avez généralement des limites du type taille maximale d’upload et temps d’exécution. Côté serveur, il y a souvent des limites de taille de requête. WordPress a aussi des comportements internes autour du traitement.

Dans la pratique, je conseille d’aligner les limites sur un ratio réaliste avec votre usage. Un site de blog peut raisonnablement limiter la taille à un seuil qui correspond à vos besoins éditoriaux. Un site e-commerce ou un site photo peut tolérer davantage, mais il doit alors prévoir un traitement côté image plus maîtrisé (redimensionnement, génération de tailles, compression contrôlée).

Le point important: si vous mettez des limites PHP “au petit bonheur”, vous risquez des erreurs frustrantes. L’objectif est de refuser proprement, avec des messages cohérents, plutôt que de laisser le serveur tomber.

Plugins et conversions: là où les risques se déplacent

Une partie du travail de sécurisation WordPress passe par un tri lucide des plugins qui touchent aux médias. Quand un plugin intervient dans la chaîne, vous devez décider s’il est indispensable, maîtrisé et maintenu.

Trois scénarios reviennent souvent:

Plugins d’import (from URL, synchronisation externe). Outils de redimensionnement et d’optimisation d’images. Builders qui importent des assets et les re-packagent.

Le problème n’est pas “le plugin” en soi. Le problème est la combinaison: plugin + configuration serveur + validation. Un plugin peut croire qu’il a une image et déclencher une conversion via une commande système, ou repasser par un processus de traitement où un détail de parsing devient exploitable.

Si votre environnement utilise des outils externes comme ImageMagick, le risque n’est pas uniquement l’upload, c’est aussi le traitement. Des réglages et une configuration sécurisée de l’outil sont nécessaires. Selon votre hébergeur, vous n’aurez pas la même liberté. Mais au minimum, vous devez vérifier que les conversions sont contrôlées et que les formats “périlleux” sont gérés de manière cohérente.

Ne pas oublier l’URL: ce qui est servi doit rester inoffensif

Même un fichier parfaitement “validé” peut poser problème si votre serveur le sert d’une manière inattendue. Les en-têtes HTTP et la manière dont le serveur déduit le type de contenu comptent.

Si un fichier est servi comme text/html au lieu de image/png, le navigateur peut mal interpréter. Si l’en-tête content-type est incohérent, vous créez une zone d’ambiguïté. Dans la plupart des cas, le serveur déduit le type de contenu en fonction de l’extension, parfois aussi du contenu. La cohérence entre ce que vous autorisez à uploader et ce qui est servi est un point de vigilance.

Un bon test consiste à exécuter des uploads en préproduction, puis à inspecter https://gardewp.fr/securite-wordpress/ les en-têtes et le rendu. Ce n’est pas glamour, mais c’est très révélateur.

Mettre en place une politique d’upload cohérente

Il faut une politique, pas seulement un ensemble de réglages. Une politique, c’est un choix assumé: quels formats, quelles tailles, qui peut uploader, et où ces fichiers peuvent être utilisés.

image

Dans WordPress, on peut aussi jouer sur la capacité des rôles. Un contributeur n’a pas forcément besoin d’uploader tous les formats. Un auteur peut publier des images, mais un éditeur ne devrait pas nécessairement ajouter des fichiers sensibles. En pratique, restreindre les rôles qui peuvent upload des médias plus risqués est souvent un gain rapide.

Le meilleur compromis dépend de votre organisation. Si vous avez une équipe marketing qui doit gérer des documents et des visuels, vous aurez des besoins plus larges. Si vous gérez tout en interne avec peu de personnes, vous pouvez resserrer davantage.

Voici un mini cadre de décision, utile quand vous devez trancher:

    Refuser ce qui n’est pas nécessaire, même si ça “arrange” sur le moment. Autoriser ce qui est nécessaire, avec validation stricte et cohérence de service. Renforcer la protection contre les uploads volumineux et répétitifs. Vérifier comment le serveur traite les extensions dans uploads.

Checklist de durcissement rapide (à faire en préproduction)

Pour éviter les oublis, j’aime bien passer par un atelier court, en environnement de test, avant de toucher au site en production.

    Vérifier que l’exécution PHP est impossible dans wp-content/uploads (test contrôlé). Confirmer les tailles maximales côté PHP et côté serveur, puis aligner WordPress. Tester des uploads “incohérents” (mauvaise extension, MIME volontairement faux). Inspecter les en-têtes HTTP et s’assurer que le content-type servi reste cohérent. Mettre à jour WordPress et supprimer ou mettre en maintenance les plugins inutiles liés aux médias.

Cette phase permet de repérer les problèmes sans casser votre production. Et surtout, elle met en évidence les erreurs de réglage qui ne se voient pas en lisant une configuration.

Sécuriser sans bloquer l’édition: les pièges d’un durcissement trop agressif

Quand on renforce la sécurité, le risque inverse apparaît: empêcher des usages légitimes. Les images importées d’outils externes peuvent être parfois “mal étiquetées” sur le plan des métadonnées. Certaines photos venant d’appareils ou d’applications de retouche peuvent contenir des profils de couleurs inhabituels, des dimensions exotiques, ou des structures internes particulières. Si vous appliquez une validation trop stricte, vous allez générer des échecs et donc du travail manuel.

Autre piège: les environnements où le redimensionnement à la volée échoue à cause de dépendances manquantes. Dans ce cas, l’upload peut passer, mais le traitement échoue ensuite. Vous devez décider: est-ce que vous forcez l’upload à être valide seulement si le traitement réussit, ou est-ce que vous autorisez l’upload mais vous mettez un mécanisme de correction plus tard?

Mon approche est pragmatique: commencer par sécuriser le “stade d’entrée” (ce qui peut être uploadé) et l’“exécution” (ce qui peut être interprété). Ensuite, affiner la qualité (contrôle du format réel, cohérence des dimensions) sans rendre le site inutilisable.

Sécurité applicative: limiter les droits et réduire la valeur d’un compte compromis

Même si vous sécurisez l’upload parfaitement, un compte compromis peut tenter des actions dans l’admin. Le hardening du fichier ne compense pas le manque de contrôle sur les accès.

Deux leviers sont souvent efficaces:

D’abord, limiter les rôles qui peuvent uploader des médias plus “risqués”. Un site à plusieurs auteurs peut être configuré pour que seuls certains profils puissent ajouter des fichiers plus étendus.

Ensuite, durcir les contrôles d’authentification et limiter les attaques par force brute. Cela ne concerne pas directement le fichier en lui-même, mais cela réduit les chances qu’un attaquant arrive à injecter ce qu’il veut.

Je sais que ces points semblent “à côté” de l’upload. Pourtant, dans les enquêtes incident, l’exécution réelle ne se fait souvent que si l’attaquant a déjà une capacité d’accès suffisante pour déclencher des uploads.

Quid des API et des uploads automatisés

WordPress vit beaucoup via l’API. Même si vous verrouillez l’interface d’admin, une application externe peut appeler l’endpoint d’upload. Si vous autorisez des intégrations, il faut vérifier que les validations se déclenchent de la même manière.

Dans plusieurs projets, le chemin “automatisé” avait une validation moins stricte que le chemin “admin”. Ça arrive parce que les développeurs front ont pris un raccourci, ou parce qu’un plugin a implémenté sa propre logique.

La stratégie consiste à tester avec de vrais flux. Pas seulement le navigateur, mais aussi l’intégration que vous utilisez réellement. Vous pouvez alors confirmer que les mêmes contraintes s’appliquent, tailles comprises, et que l’endroit de stockage reste le même.

Exemple de traitement réaliste: gérer la compression et les formats sans ouvrir la porte

Une approche qui fonctionne bien consiste à séparer le sujet “acceptation” et le sujet “résultat”. Vous pouvez autoriser un format d’entrée dans une limite contrôlée, puis le convertir vers un format plus sûr et cohérent, si votre chaîne de traitement le permet.

image

Par exemple, vous pouvez accepter un JPEG et le convertir en JPEG optimisé, ou le convertir en WebP en fonction des capacités du serveur. Ça réduit le stockage, améliore les performances, et diminue les surprises de rendu.

Mais, et c’est un point important, la conversion est une nouvelle étape où des bugs peuvent apparaître. D’où l’importance de sécuriser le traitement, de limiter les tailles et de surveiller les logs en cas d’échec.

Surveillance: voir les comportements anormaux avant l’incident

La sécurité n’est pas seulement “bloquer”. C’est aussi “observer”. Les uploads anormaux se remarquent souvent: pics d’erreurs, fichiers rejetés en rafale, tentatives multiples, extensions inattendues, ou volumes inhabituels.

Vous pouvez exploiter plusieurs signaux sans forcément mettre en place un SIEM complet. Les logs PHP, les logs du serveur web, et les journaux d’audit d’un plugin de sécurité (si vous en utilisez un) suffisent souvent à détecter une campagne.

J’ai vu des sites qui n’étaient pas “cassés” en 24 heures, mais qui montraient déjà un schéma de tentatives. Les équipes ont pu corriger avant que la compromission ne soit installée.

Deux règles d’or que j’applique presque toujours

Je les formule simplement parce qu’elles évitent 80% des mauvais choix:

Un upload doit être traité comme une donnée non fiable jusqu’au moment où le serveur confirme qu’il s’agit bien du type attendu et qu’il est stocké de manière inoffensive. Le serveur doit être configuré pour ne jamais exécuter le contenu déposé dans les médias.

Ces deux règles ne dépendent pas de tel ou tel plugin. Elles deviennent une base, sur laquelle vous pouvez ensuite ajuster finement.

Mini check final avant de publier le durcissement

Si vous avez fait les réglages et que vous êtes prêt à basculer en production, voici un dernier passage utile, court, pour éviter les surprises côté contenu et côté technique:

    Faites un test avec vos médias habituels (formats réels, tailles réelles) et vérifiez l’édition. Testez aussi un upload “refusé” (mauvais type) et vérifiez que le site répond proprement. Contrôlez l’accessibilité des fichiers (URL, rendu, en-têtes) après changement. Vérifiez les logs après 24 heures, même si “tout a l’air bon”. Assurez-vous que les rôles autorisés correspondent à votre organisation (qui peut uploader quoi).

Ce que ça change concrètement pour un site WordPress

Une bonne sécurisation de l’upload ne se voit pas toujours immédiatement. Le bénéfice est souvent dans la tranquillité: moins de doute sur la façon dont un fichier est interprété, moins de scénarios où une extension devient une exécution, et une réduction nette de la surface d’attaque.

Et il y a un second effet, plus subtil: vous améliorez aussi la qualité opérationnelle. En clarifiant ce que vous acceptez et pourquoi, vous facilitez le travail des auteurs. Vous évitez les échanges “le fichier passe chez moi et pas chez toi”. Vous donnez un cadre stable, qui réduit les tickets et les contournements.

Si vous devez retenir une idée, c’est celle-ci: sécuriser l’upload des médias, c’est construire une chaîne cohérente, serveur compris, où chaque étape confirme le bon sens du précédent. Quand cette cohérence existe, les attaques perdent en efficacité, et votre site gagne en résilience.