Protection Site WordPress : Mettre des limites sur la taille des uploads

Quand un site WordPress prend de l’ampleur, les fichiers deviennent un vrai sujet de sécurité et de maîtrise. Un formulaire d’upload, un plugin mal paramétré, ou simplement un utilisateur dont le navigateur envoie une taille inattendue, et tout peut basculer. Les risques ne se résument pas à “l’upload refuse” ou “ça passe”. Il y a aussi la charge serveur, la stabilité, la gestion du stockage, et la capacité d’un attaquant à saturer la connexion ou le disque.

Limiter la taille des uploads est l’un des gestes les plus rentables pour une protection site WordPress. C’est une mesure simple, mais elle touche plusieurs couches: PHP, WordPress, parfois le proxy (Nginx) et le stockage. L’objectif est clair: empêcher les fichiers trop gros d’atteindre inutilement le traitement applicatif, tout en conservant une expérience correcte pour les cas légitimes.

Le problème, vu depuis le serveur

Sur WordPress, un upload suit généralement une chaîne assez longue: le navigateur envoie un flux, le serveur web le relaie, PHP reçoit la requête, WordPress vérifie les capacités, puis finalement le fichier est écrit sur le disque (ou vers un backend si vous utilisez un S3 compatible via un plugin). Si une limite n’est fixée qu’au dernier moment, vous payez quand même le coût des premières étapes.

Dans la pratique, j’ai déjà vu des sites qui “accepteraient” des uploads très gros selon WordPress, puis finissaient par échouer côté PHP pendant le traitement. Résultat: pages qui se chargent longtemps, erreurs parfois peu explicites, et parfois des tentatives répétées côté front, ce qui aggrave la charge. La version plus solide consiste à fixer des limites cohérentes sur plusieurs niveaux, afin que l’échec soit rapide, lisible et contrôlé.

Autre angle: la sécurité. Un attaquant n’a pas besoin de réussir un exploit complexe pour causer des dégâts. Envoyer des fichiers de grande taille, répéter des tentatives, et exploiter des comportements de plugins d’upload, peut conduire à une saturation. Même si le fichier est refusé, la requête a déjà consommé du temps CPU, de la bande passante, des buffers mémoire, et des ressources I/O.

Mettre des limites n’empêche pas toutes les attaques. Mais ça réduit fortement la surface utile pour les tentatives “lourdes”.

image

Décider d’une taille réaliste

Avant de toucher à la configuration, il faut arbitrer. “Limiter à 2 Mo” peut sembler propre, mais si votre site héberge des images de qualité, des PDF de documents, ou des médias liés à des fiches produit, vous allez déclencher des refus frustrants. À l’inverse, “limiter https://gardewp.fr/securite-wordpress/ à 100 Mo” peut être trop permissif si vous voulez limiter les impacts d’abus.

Mon approche consiste à partir des usages réels, puis à ajouter une marge raisonnable. Exemple concret: sur un site vitrine, les images sont souvent compressées et redimensionnées en amont. Des formats comme WebP ou JPEG bien réglés restent généralement dans une enveloppe modeste. Là, une limite autour de 5 à 20 Mo peut suffire selon votre flux éditorial. Sur un site associatif avec des pièces jointes, des PDF ou des exports peuvent justifier 20 à 50 Mo, voire plus. Le bon chiffre dépend aussi de votre politique de taille moyenne des médias.

Attention aussi au “gros fichier” inattendu. Certains utilisateurs envoient par erreur un fichier vidéo, ou un export bureautique non compressé. Une limite trop haute laisse passer des cas marginaux qui finissent en consommation de stockage.

Le point clé n’est pas seulement le nombre, c’est la cohérence entre les couches.

Les leviers WordPress: taille d’upload côté application

WordPress impose déjà des contraintes via des constantes PHP et des paramètres internes. Les deux principaux que vous verrez sont la taille maximale des fichiers et la taille maximale de la requête.

Dans WordPress, les valeurs pertinentes sont souvent liées à upload_max_filesize et à post_max_size côté PHP. Si PHP ne laisse pas passer une requête, WordPress ne pourra pas “contourner”.

À l’échelle WordPress, il existe aussi des filtres et des réglages (selon les versions et les contextes) pour ajuster les limites. Mais dans le monde réel, quand je dois “mettre des limites” sur un site, je commence par la partie qui gouverne vraiment le flux: PHP et, si présent, le serveur web en amont.

La cohérence avec php.ini ou les valeurs de pool PHP

Selon l’hébergement, vous ne modifiez pas la même chose. Sur un hébergement partagé, il est fréquent que vous n’ayez pas d’accès direct à php.ini. Sur un VPS, vous pouvez. Dans tous les cas, l’idée est identique: limiter les variables PHP qui contrôlent la taille.

Les variables que vous verrez le plus sont:

    upload_max_filesize pour la taille maximale d’un fichier uploadé post_max_size pour la taille maximale totale d’un POST max_execution_time et max_input_time pour le temps accordé au traitement de l’entrée, utile quand les fichiers sont proches de la limite

Si vous réglez upload_max_filesize à 20 Mo mais que post_max_size reste à 16 Mo, vous aurez un comportement surprenant: WordPress peut croire que 20 Mo est autorisé, mais le POST total dépasse. Inversement, si post_max_size est trop élevé par rapport à upload_max_filesize, la requête peut passer la limite de POST mais échouer au moment du fichier. Les deux cas sont mauvais, mais le second est souvent moins “douloureux” pour l’erreur.

Mon conseil: fixez post_max_size légèrement au-dessus de upload_max_filesize, de façon à absorber l’overhead (données de requête, encodage). Selon les configurations, un écart de quelques Mo à une dizaine de Mo est généralement plus prudent.

Côté serveur web: où les limites se jouent aussi

WordPress n’est pas seul. Si vous avez un proxy ou un reverse proxy, par exemple Nginx devant PHP-FPM, Nginx peut refuser une requête avant même d’arriver à PHP. Dans ce cas, le réglage côté PHP ne change rien.

Sur Nginx, on rencontre souvent des directives de type client_max_body_size. Sur Apache, ce sont plutôt les limites liées au module PHP ou des directives en fin de chaîne. L’enjeu reste le même: la limite la plus “petite” dans la chaîne finit par gagner. Donc si Nginx accepte 200 Mo, mais PHP en refuse 20, vous verrez une erreur PHP. Si Nginx refuse 10 Mo, vous verrez une erreur au niveau du serveur web, parfois avec un message différent.

Je recommande de vérifier au moins deux choses avant d’ajuster: quelle couche reçoit les requêtes, et comment elles échouent. Un test simple, par exemple avec un fichier légèrement au-dessus de la limite visée, peut clarifier très vite où la coupure se fait. Sur certains sites, le symptôme “erreur 413” indique un refus au niveau reverse proxy, là où un message PHP indique plutôt un contrôle PHP.

Multisite et rôles: limites qui se mélangent

Si vous utilisez WordPress Multisite, les uploads peuvent être influencés à la fois par les réglages globaux et par des paramètres réseau. Dans ce contexte, une limite “trop permissive” peut transformer un problème local en problème global. Un site du réseau peut avoir un comportement “normal”, tandis qu’un autre reçoit des médias plus lourds, et déclenche des erreurs partout.

image

Une autre subtilité concerne les rôles et les capacités. WordPress permet de distinguer qui peut uploader quoi, et quels types de fichiers sont autorisés. Mais la capacité et la taille ne sont pas la même dimension. Un utilisateur autorisé à uploader peut encore être bloqué par taille, et c’est normal. Ce qui compte est la cohérence de votre politique: autoriser des médias, mais refuser les cas déraisonnables avec des messages qui ne cassent pas l’interface.

Si vous jouez sur “types de fichiers” et “taille maximale”, vous améliorez le contrôle global. Mais si vous ne fixez que la taille, un fichier autorisé peut rester utile pour un attaquant si la taille limite est trop haute. La taille est une barrière d’abord de performance et de coût.

Où intervenir dans WordPress: cas typiques

Il y a plusieurs endroits possibles pour intervenir selon votre accès.

Configuration serveur (souvent la meilleure porte d’entrée)

Sur un environnement maîtrisé, le plus efficace est de régler directement les variables PHP et éventuellement client_max_body_size. C’est “en amont”, donc c’est rapide et moins coûteux.

Le point délicat, c’est que vous devez connaître votre stack réelle. Sur un hébergement géré, vous n’avez parfois accès qu’à l’interface de gestion PHP. Sur un VPS, c’est plus direct. Sur un site en mode “couche de contrôle” (reverse proxy ou CDN), les limites peuvent être dispersées. Un CDN peut avoir aussi des limites de taille de requête, selon le mode d’intégration.

Dans ce type de situation, je garde un principe simple: je ne modifie pas cinq paramètres au hasard. Je change un réglage, je teste, puis je stabilise. Ce n’est pas une question de perfection, c’est une question de diagnostic. Les erreurs d’upload sont souvent difficiles à comprendre si tout a changé d’un coup.

Ajuster via wp-config.php (utile, mais à utiliser avec mesure)

WordPress lit souvent des constantes depuis wp-config.php pour connaître certains seuils. Selon votre cas, vous pouvez aussi fixer des limites directement. Toutefois, l’idée n’est pas de “compenser” une configuration PHP trop permissive. Si PHP accepte des uploads énormes, votre protection restera limitée, même si WordPress applique un filtre. Vous risquez d’exposer le serveur à la requête en amont.

J’utilise wp-config.php quand je veux rendre la limite explicite au niveau application et m’assurer que WordPress affiche et traite correctement les valeurs attendues. Mais je veille à ce que PHP et le serveur web soient alignés.

Valeurs recommandées: penser en ordre de grandeur

Je ne vais pas vous donner un chiffre universel, parce qu’il n’existe pas. En revanche, je peux vous donner des repères d’ingénieur.

Si votre site publie surtout des images, une limite de quelques Mo à une vingtaine de Mo correspond souvent aux besoins réalistes, surtout si vous redimensionnez côté image et que les médias sont optimisés. Pour des PDF ou des pièces jointes, la limite peut monter plus haut, parfois 20 à 50 Mo, selon la nature des documents. Si vous avez des utilisateurs qui envoient des exports lourds, vous devrez accepter une taille plus élevée, mais alors vous devriez renforcer d’autres protections, comme le filtrage des types, des quotas, et éventuellement des mécanismes de scanning.

La question la plus importante n’est pas “limiter à X”, c’est “limiter à X et aligner les couches”. Une limite incohérente crée des comportements bizarres et augmente le coût de support.

Vérifier ce que PHP et WordPress voient réellement

Un point pratique: les valeurs affichées dans WordPress (ou dans certains plugins) ne suffisent pas à elles seules. Ce que PHP pense de upload_max_filesize et post_max_size est déterminant. Sur beaucoup de sites, vous pouvez vérifier via les pages de diagnostic ou via la ligne de commande. L’important, c’est de comparer.

Si vous modifiez une valeur dans php.ini mais que votre pool PHP utilise une autre configuration, vous ne verrez aucun effet. Si votre Nginx limite est plus basse, vous aurez des erreurs côté serveur. Dans les deux cas, vous aurez l’impression que WordPress “ignore” votre réglage, alors que ce n’est pas le cas.

Je recommande d’adopter un test reproductible: choisissez un fichier dont la taille est connue et légèrement supérieure à la limite visée (par exemple 1 à 10 Mo au-dessus selon votre échelle). Lancez un upload depuis l’interface qui échoue, puis observez l’erreur. Si le message indique une erreur de taille, vous êtes probablement sur un contrôle au bon niveau. Si vous voyez un code type 413, vous êtes plus probablement côté proxy ou serveur web. Si tout échoue sans message clair, vérifiez aussi les logs PHP et les logs du serveur web.

Paramètres de temps: la limite de taille ne suffit pas

Quand vous réduisez la taille maximale, vous réduisez aussi le temps de transfert. Mais il existe encore des cas où l’upload peut durer suffisamment longtemps pour déclencher un time-out. Par exemple, un utilisateur avec une connexion lente, ou un serveur surchargé.

C’est là que max_execution_time et max_input_time entrent en jeu. Si vous fixez une limite taille à 20 Mo, mais que vous gardez des temps très bas, un upload proche de la limite peut échouer de manière intermittente. Vous aurez alors une expérience “ça marche parfois, ça casse parfois”. Ce genre d’aléas rend les gens soupçonneux à propos du “taux d’erreur”.

L’ajustement dépend du trafic et des performances. Mais le principe reste: des limites cohérentes doivent inclure la dimension “temps”. Si vous réduisez fortement la taille, vous pouvez garder des temps raisonnables. Si vous augmentez, il faut envisager d’augmenter aussi certains seuils, sinon les utilisateurs ne comprendront pas pourquoi leurs fichiers échouent.

Types de fichiers et compatibilité: une protection utile, mais pas automatique

La taille n’est pas tout. WordPress et les plugins peuvent refuser certains types via la configuration, ou vous pouvez définir des listes. Même si vous limitez la taille, un fichier autorisé peut être très utilisé pour des abus, par exemple des fichiers qui déclenchent des traitements dans des plugins.

La bonne pratique est de limiter à la taille, puis de limiter aussi aux types réellement nécessaires à votre site. C’est particulièrement vrai si vos utilisateurs peuvent uploader via des formulaires front. Dans ce cas, le risque n’est pas seulement l’upload, c’est l’activation éventuelle de traitements, la génération de miniatures, l’extraction de métadonnées, ou la conversion.

Une observation de terrain: les filtres de type peuvent casser des usages légitimes. Un utilisateur envoie un PDF “un peu spécial”, une image avec profil colorimétrique inattendu, ou un document exporté depuis un outil qui change l’encodage. Limiter trop strictement pousse à contourner, et ce contournement finit souvent par un upload vers un autre canal (cloud, lien, email). C’est pour cela que je préfère des règles “réalistes” et je teste, plutôt que de viser le 0 risque.

Un exemple concret de réglage cohérent

Prenons un cas simple. Vous voulez empêcher les uploads de dépasser environ 20 Mo, mais vous souhaitez éviter les échecs incohérents.

La logique à suivre est:

    fixez la taille maximale côté fichier à un niveau cohérent fixez la taille maximale de requête légèrement au-dessus vérifiez qu’aucune couche en amont n’est plus restrictive testez avec un fichier juste au-dessus de la limite

Concrètement, selon vos valeurs de base, vous pourriez choisir upload_max_filesize = 20M et post_max_size = 25M (ou légèrement plus). Ensuite, si vous êtes derrière Nginx, assurez-vous que la directive correspondante dépasse la taille PHP. Enfin, dans WordPress, assurez-vous que les messages affichés correspondent à la limite réelle.

Je ne vous donne pas une recette exacte parce que chaque environnement a son overhead et sa configuration. Mais je peux vous dire comment je fais pour éviter les mauvaises surprises: je garde un petit “buffer” sur la taille de requête, et je vérifie systématiquement le niveau le plus en amont.

Ajuster selon le mode d’hébergement

Sur un hébergement mutualisé géré, vous avez parfois un panneau de configuration qui expose directement upload_max_filesize. Sur un hébergement plus “nu”, vous pouvez ajuster php.ini, ou une configuration par pool. Sur un container, la logique de montage de configuration change.

Si vous n’avez pas de contrôle total sur le serveur, une autre voie consiste à utiliser des paramètres WordPress et des hooks de validation. Mais je le dis sans détour: dans une stratégie de protection site WordPress, compter uniquement sur WordPress est rarement suffisant. La requête doit idéalement être bloquée avant d’arriver à l’application, sinon l’impact “ressource” existe quand même.

Donc, même si WordPress peut vous aider à affiner l’expérience utilisateur, la barrière principale doit être au bon niveau.

Checklist rapide avant de changer la prod

Quand vous intervenez sur une configuration d’upload, je conseille une approche méthodique. Une petite checklist évite beaucoup d’aller-retours.

image

    Identifier la couche qui reçoit l’upload (PHP-FPM, reverse proxy, CDN éventuel) Mettre une limite de taille de fichier et une limite de taille de requête cohérentes Vérifier les temps d’exécution et les entrées si des échecs intermittents apparaissent Tester avec un fichier légèrement au-dessus de la limite visée Contrôler les logs pour savoir où l’échec se produit exactement

Cette discipline change tout, surtout si plusieurs équipes touchent la configuration.

Cas limites: erreurs “bizarres” et comportements inattendus

Il y a quelques scénarios que je vois revenir.

Premier cas: vous réduisez upload_max_filesize mais vous continuez à voir des uploads “passer” depuis certains parcours de l’interface. Souvent, c’est parce que l’upload ne passe pas par la même route applicative. Par exemple, un plugin gère l’upload via une API ou un flux différent. Il se peut aussi que certains formats soient traités différemment (compression côté client ou serveur). Dans ce cas, vous devez chercher comment l’upload est réellement implémenté.

Deuxième cas: les erreurs affichées sont trompeuses. WordPress peut afficher une limite basée sur ses réglages, mais le serveur échoue avant. Résultat, l’utilisateur voit “fichier trop gros” alors que la cause exacte est côté proxy. Inversement, l’utilisateur peut voir un échec de connexion sans message explicite. Les logs sont indispensables.

Troisième cas: vous êtes en multisite et seule une partie du réseau se plaint. Souvent, la configuration PHP est commune, mais les utilisateurs et les tailles attendues ne le sont pas. Vous devez alors harmoniser la politique de téléchargement et ajuster, au besoin, des limites par rôle ou par type de contenu.

Ces cas ne sont pas des exceptions rares. Ils font partie de la réalité opérationnelle.

Et si vous voulez aller plus loin que la taille?

Limiter la taille est un excellent point de départ, mais c’est rarement la dernière marche. Selon votre contexte, vous pouvez combiner plusieurs mesures: contrôle des rôles, restrictions de types, quotas, limitation du nombre d’uploads par période, et validation côté front pour éviter des requêtes inutiles.

Mais gardez une règle de bon sens: chaque couche ajoutée complexifie le diagnostic. Si vous ajoutez un quota, un filtrage de types, une validation front, et une taille côté serveur, et que ça échoue, vous devez être capable de dire quelle règle a bloqué et pourquoi. Donc le mieux est d’implémenter par étapes, pas tout d’un coup.

La taille est une barrière fondamentale, et souvent la plus simple à expliquer.

Conclusion implicite: une barrière efficace, un système lisible

Mettre des limites sur la taille des uploads sur WordPress, ce n’est pas seulement “éviter les gros fichiers”. C’est une façon de rendre le site plus stable, plus résilient face aux abus, et plus cohérent pour les utilisateurs. La clé, c’est la cohérence: PHP, serveur web, éventuellement proxy, et WordPress doivent parler le même langage.

Si vous faites les réglages une fois, puis que vous testez avec un fichier proche de la limite, vous obtenez un système prévisible. Et cette prévisibilité est un avantage de sécurité autant qu’un avantage de maintenance.

Si vous me dites votre contexte (hébergement partagé, VPS, Nginx devant Apache, présence de CDN, utilisation de Multisite), je peux vous proposer une stratégie de limites avec des valeurs à calibrer et la meilleure façon de les vérifier, sans bricoler au hasard.