Catégorie

Sécurité

Mécanismes de sécurité : chiffrement AES-256-GCM, rate limiting IP, CSRF, sanitisation SVG et gestion des sessions.

La sécurité d'un CMS ne s'improvise pas en fin de projet — elle se conçoit dès la première ligne de code. QuietCMS applique ce principe de manière radicale : chaque vecteur d'attaque connu a fait l'objet d'une contre-mesure dédiée, intégrée au cœur du système bien avant la première version publique. Pas de plugin de sécurité à installer, pas de configuration post-déploiement à ne pas oublier. La protection est active par défaut, dès l'installation.

L'approche de QuietCMS en matière de sécurité repose sur un principe central : la défense en profondeur. Aucun mécanisme unique ne protège le système en entier. Huit couches de protection indépendantes opèrent simultanément. Si l'une d'elles venait à être contournée — par une vulnérabilité inconnue ou une erreur de configuration — les sept autres restent en place. La compromission d'un mécanisme ne signifie pas la compromission du système.

Chiffrement AES-256-GCM — confidentialité et intégrité combinées

Les données sensibles au repos — clés API des fournisseurs IA, mots de passe SMTP — sont chiffrées avec AES-256-GCM (Authenticated Encryption with Associated Data). Ce mode de chiffrement est particulièrement bien choisi : contrairement à AES-CBC ou AES-CTR, GCM garantit simultanément la confidentialité (personne ne peut lire le texte chiffré) et l'intégrité (toute modification du texte chiffré est détectée). Un attaquant qui parviendrait à lire settings.json ne verrait que du binaire encodé en base64 — inutilisable sans la clé de déchiffrement.

La clé de 256 bits est générée lors de l'installation avec random_bytes(32), la source d'entropie la plus fiable disponible en PHP. Elle est stockée dans config.php, en dehors de la racine web accessible par Apache ou Nginx. Chaque opération de chiffrement utilise un IV (vecteur d'initialisation) de 96 bits unique, généré aléatoirement, qui est concaténé au texte chiffré avec le tag d'authentification GCM de 128 bits. Le payload final est encodé en base64 pour le stockage JSON : base64(IV || TAG || CIPHERTEXT).

URL d'administration randomisée — obscurité légitime

Le back-office de QuietCMS n'est jamais accessible à /admin/. À l'installation, un segment d'URL de 12 caractères aléatoires est généré et injecté dans .htaccess via mod_rewrite. Ce slug unique — par exemple /a7f3k9x2mq4p/ — est la seule entrée vers l'interface d'administration. L'accès direct à /admin/ retourne une 404 ou est bloqué au niveau du serveur web.

Cette technique, parfois critiquée comme de la « sécurité par l'obscurité », est ici complémentaire aux autres protections et non pas substituée à elles. Elle élimine mécaniquement les attaques de force brute automatisées qui ciblent les chemins d'admin par défaut — ce qui représente une fraction significative des attaques réelles contre les CMS. Le slug admin n'est jamais exposé dans robots.txt, sitemap.xml ou les balises HTML des pages publiques.

Rate limiting IP persistant

Les tentatives de connexion répétées — qu'elles visent le back-office ou l'espace lecteur — sont limitées par un mécanisme de rate limiting IP. Au-delà de 5 tentatives échouées en 15 minutes, l'adresse IP est temporairement bloquée. Les compteurs persistent dans un fichier JSON sur disque, ce qui les rend impossibles à contourner en supprimant les cookies ou en ouvrant une nouvelle session.

Les adresses IP ne sont pas stockées en clair — elles sont hachées avec SHA-256 et tronquées à 16 caractères hexadécimaux. Ce choix est conforme au RGPD (une adresse IP est une donnée personnelle) tout en conservant l'efficacité du blocage. Le même mécanisme s'applique aux requêtes de réinitialisation de mot de passe, évitant l'énumération des comptes par timing d'attaque.

Tokens CSRF — protection contre les requêtes forgées

Chaque formulaire POST du back-office embarque un token CSRF unique, généré avec random_bytes(32) et stocké en session côté serveur. La vérification utilise hash_equals() — une comparaison en temps constant qui neutralise les attaques par analyse temporelle (timing attacks), où un attaquant mesure le temps de réponse pour deviner des caractères du token un par un.

Les formulaires publics (FormManager) utilisent un token CSRF distinct, isolé de la session administrative. Cette séparation garantit qu'une fuite d'un token de formulaire public ne compromet pas l'interface d'administration — et inversement.

Sanitisation SVG — neutralisation des XSS vectoriels

Les fichiers SVG sont un vecteur d'attaque XSS souvent sous-estimé. Un SVG malveillant peut contenir des balises <script>, des attributs onload ou des URI javascript: qui s'exécutent dans le navigateur dès que le fichier est rendu en ligne dans une page HTML. QuietCMS analyse tous les SVG uploadés avec DOMDocument et XPath avant de les enregistrer.

Sont supprimés : les balises <script> et <foreignObject>, tous les attributs événementiels (onclick, onload, onmouseover…), et toute valeur javascript: ou data:text/html dans les attributs href, src, action et data. Un SVG qui ne peut pas être parsé par DOMDocument est rejeté et supprimé du disque immédiatement.

Régénération de session et prévention de la fixation

À chaque connexion — administrateur ou lecteur — QuietCMS appelle session_regenerate_id(true). L'ancien identifiant de session est immédiatement invalidé. Cette pratique élimine les attaques de session fixation, où un attaquant force une victime à utiliser un ID de session qu'il contrôle pour ensuite s'approprier la session authentifiée.

Les cookies de session sont configurés avec les attributs HttpOnly (inaccessibles depuis JavaScript), SameSite=Strict (non transmis dans les requêtes cross-site) et Secure (HTTPS uniquement). Ces trois attributs combinés éliminent les vecteurs d'attaque classiques sur les cookies d'authentification.

En-têtes HTTP de sécurité

Les en-têtes HTTP de sécurité sont configurés dans le .htaccess et s'appliquent à toutes les réponses du serveur, sans exception :

  • Content-Security-Policydefault-src 'self', object-src 'none', base-uri 'self'
  • X-Frame-Options: SAMEORIGIN — prévention du clickjacking
  • X-Content-Type-Options: nosniff — interdit au navigateur de deviner le MIME type
  • Referrer-Policy: strict-origin-when-cross-origin — limite les informations transmises dans l'en-tête Referer
  • Permissions-Policy — désactive géolocalisation, caméra et microphone

Maintenir la sécurité dans la durée

La sécurité n'est pas un état — c'est une pratique continue. Les mécanismes intégrés à QuietCMS couvrent les vecteurs d'attaque connus au moment du développement, mais de nouvelles vulnérabilités émergent en permanence dans l'écosystème PHP et dans les serveurs web. Voici les recommandations pour maintenir un niveau de protection élevé sur la durée.

Mises à jour du serveur web et de PHP

QuietCMS ne peut pas vous protéger des vulnérabilités dans PHP lui-même ou dans Apache/Nginx. Maintenez PHP en version active (8.1 minimum, 8.3 recommandé) et appliquez les patches de sécurité du serveur web dès leur publication. Un hébergement mutualisé géré applique généralement ces mises à jour automatiquement — vérifiez la politique de votre hébergeur.

HTTPS obligatoire

QuietCMS est conçu pour fonctionner derrière HTTPS. L'attribut Secure sur les cookies de session est automatiquement actif, mais il ne protège les sessions que si le transport est effectivement chiffré. Configurez une redirection HTTP → HTTPS au niveau du serveur web et, idéalement, activez HSTS (Strict-Transport-Security) pour prévenir les attaques de downgrade.

Permissions des fichiers

Le répertoire content/ doit être accessible en lecture/écriture par le processus PHP (typiquement www-data), mais pas accessible directement par le navigateur. Le .htaccess de QuietCMS bloque l'accès direct aux fichiers JSON de contenu. Vérifiez que les permissions système (chmod) n'accordent pas de droits excessifs — 755 pour les répertoires et 644 pour les fichiers est un bon point de départ.

Surveiller les logs

Les erreurs PHP et les accès suspects sont journalisés dans content/logs/php_error.log. Ce fichier est protégé contre l'accès direct par le .htaccess, mais il doit être surveillé régulièrement. Un volume inhabituellement élevé d'erreurs 404 sur des chemins d'admin connus (/wp-admin/, /administrator/…) indique une tentative de scan automatisé — QuietCMS y résiste nativement grâce au slug randomisé.

Sauvegardes chiffrées

La simplicité du modèle de stockage flat-file rend la sauvegarde triviale : un rsync ou un zip du dossier suffit. Pensez à chiffrer les archives de sauvegarde si elles transitent ou sont stockées sur des infrastructures tierces — elles contiennent les données chiffrées mais aussi la clé de déchiffrement dans config.php.

Content Security Policy à base de nonce

La Content Security Policy (CSP) est l'une des défenses les plus efficaces contre l'exécution de scripts injectés. QuietCMS applique sur le front une CSP stricte fondée sur un nonce : à chaque requête, une valeur aléatoire est générée et associée aux scripts légitimes de la page. Un script qui ne porte pas ce nonce — typiquement un script injecté par une attaque — n'est tout simplement pas exécuté par le navigateur. Couplé à la directive strict-dynamic, ce mécanisme autorise les scripts chargés dynamiquement par du code de confiance, ce qui permet de faire fonctionner les outils tiers légitimes sans rouvrir la porte à l'injection.

La directive 'unsafe-inline' reste présente uniquement comme repli pour les navigateurs anciens qui ignorent les nonces ; sur les navigateurs modernes, la présence d'un nonce la neutralise automatiquement. Cette stratégie dite « nonce + strict-dynamic » représente l'état de l'art en matière de CSP : elle est à la fois robuste face aux attaques et tolérante vis-à-vis des intégrations réelles. L'en-tête est défini côté PHP, ce qui permet de générer un nonce différent à chaque réponse plutôt que de figer une valeur statique.

Échappement systématique des sorties

Une CSP est une seconde ligne de défense ; la première reste l'échappement rigoureux des données à l'affichage. QuietCMS applique le principe selon lequel toute donnée d'origine non fiable — commentaire de visiteur, valeur de formulaire, référent HTTP, agent utilisateur, message d'erreur — est convertie en entités HTML avant d'être insérée dans une page. Un commentaire contenant une balise de script est ainsi rendu inerte : il s'affiche comme du texte et ne s'exécute jamais. Cette discipline s'applique aussi bien au site public qu'aux écrans d'administration, où une attaque par script stocké serait particulièrement grave puisqu'elle s'exécuterait dans la session d'un administrateur authentifié.

Le soin porté à ce détail va jusqu'aux liens construits à partir de données externes. Un référent forgé en javascript: ne devient jamais un lien cliquable : le schéma de l'URL est validé, et seuls http et https sont autorisés à former un lien, le reste étant affiché en texte simple. Cette vérification ferme une faille subtile que l'échappement HTML seul ne couvre pas, puisqu'il n'empêche pas un schéma d'URL dangereux.

Hachage des mots de passe et authentification

Les mots de passe des administrateurs ne sont jamais stockés en clair ni avec un algorithme de hachage rapide détourné. QuietCMS s'appuie sur bcrypt, conçu spécifiquement pour le hachage de mots de passe : sa lenteur volontaire et son facteur de coût ajustable rendent les attaques par force brute hors ligne extrêmement coûteuses, même si le fichier de comptes venait à fuir. Chaque empreinte intègre un sel unique, ce qui interdit l'usage de tables précalculées et garantit que deux administrateurs ayant le même mot de passe possèdent des empreintes différentes.

L'authentification est complétée par un rate limiting par adresse IP, qui ralentit puis bloque temporairement les tentatives répétées, et par la régénération de l'identifiant de session après connexion, qui prévient les attaques par fixation de session. Ces mesures forment un ensemble cohérent : même en connaissant l'URL d'administration randomisée, un attaquant se heurte à un mot de passe robustement haché, à une limitation des tentatives et à une gestion de session durcie.

Le flat-file comme réduction de la surface d'attaque

L'absence de base de données n'est pas qu'un choix d'architecture : c'est aussi une décision de sécurité. La catégorie entière des injections SQL, qui figure parmi les vulnérabilités web les plus répandues et les plus dévastatrices, n'a tout simplement pas de prise sur QuietCMS, faute de moteur SQL à attaquer. Il n'y a pas de chaîne de connexion à protéger, pas de privilèges de base de données à configurer, pas de port de base de données potentiellement exposé. Chaque composant absent est une vulnérabilité potentielle en moins.

Cette philosophie de minimalisme s'étend aux dépendances. Moins une application embarque de bibliothèques tierces, moins elle hérite de failles découvertes en amont et moins elle dépend de la réactivité de mainteneurs externes pour ses correctifs de sécurité. QuietCMS assume ce parti pris : la sobriété fonctionnelle se traduit directement en sobriété de la surface d'attaque.

Audit, journalisation et réponse à incident

La sécurité ne s'arrête pas à la prévention ; elle inclut la capacité à détecter et à réagir. Le journal d'accès, le journal des robots et le journal des erreurs PHP offrent ensemble une visibilité sur le comportement du site et sur les tentatives suspectes. Une recrudescence d'erreurs 404 sur des chemins sensibles, un pic de trafic depuis un sous-réseau inhabituel ou des erreurs PHP inattendues sont autant de signaux qu'un administrateur attentif peut interpréter avant qu'un incident ne s'aggrave.

En cas de compromission suspectée, la nature flat-file simplifie la réponse : on peut comparer les fichiers à une sauvegarde saine pour repérer toute modification, faire tourner l'URL d'administration et les identifiants, et restaurer un état antérieur en transférant un dossier. Cette traçabilité et cette réversibilité, combinées aux couches de défense en profondeur décrites plus haut, font de la sécurité de QuietCMS un système cohérent où chaque mesure renforce les autres plutôt qu'une simple juxtaposition de fonctionnalités.