Limiter les scripts intersites (XSS) avec une CSP (Content Security Policy) stricte.

Navigateurs pris en charge

  • Chrome: 52
  • Edge: 79
  • Firefox: 52
  • Safari: 15.4.

Source

Script intersites (XSS) la possibilité d'injecter des scripts malveillants dans une application Web, les plus vulnérabilités de sécurité sur le Web depuis plus de dix ans.

Content Security Policy (CSP) est une couche de sécurité supplémentaire qui permet d'atténuer les attaques XSS. Pour configurer un CSP, ajouter l'en-tête HTTP Content-Security-Policy à une page Web et définir des valeurs qui contrôler les ressources que le user-agent peut charger pour cette page.

Cette page explique comment utiliser une CSP basée sur des nonces ou des hachages pour limiter les attaques XSS. Au lieu des CSP basées sur une liste d'autorisation d'hôtes, couramment utilisés, qui quittent souvent la page exposés aux XSS, car ils peuvent être contrôlés dans la plupart des configurations.

Terme clé: un nonce est un nombre aléatoire utilisé une seule fois, que vous pouvez utiliser pour marquer un Balise <script> approuvée.

Terme clé: une fonction de hachage est une fonction mathématique qui convertit une entrée. en une valeur numérique compressée appelée hachage. Vous pouvez utiliser un hachage (par exemple, SHA-256) pour marquer une Balise <script> approuvée.

Une Content Security Policy basée sur des nonces ou des hachages est souvent appelée CSP stricte. Lorsqu'une application utilise une CSP stricte, les pirates informatiques qui trouvent du code HTML les failles d'injection ne peuvent généralement pas les utiliser pour forcer le navigateur à s'exécuter des scripts malveillants dans un document vulnérable. En effet, une CSP stricte uniquement autorise les scripts hachés ou les scripts avec la valeur nonce correcte générée sur le pour que les pirates informatiques ne puissent pas exécuter le script sans connaître le bon nonce pour une réponse donnée.

Pourquoi devriez-vous utiliser une CSP stricte ?

Si votre site dispose déjà d'une CSP comme script-src www.googleapis.com, elle n'est probablement pas efficace contre les sites intersites. Ce type de CSP est appelé CSP par liste d'autorisation. Ils nécessitent beaucoup de personnalisation et peuvent être contrôlés par les pirates informatiques.

Les CSP strictes basées sur des nonces ou des hachages cryptographiques évitent ces pièges.

Structure CSP stricte

Une stratégie de sécurité du contenu stricte de base utilise l'une des réponses HTTP suivantes en-têtes:

CSP stricte basée sur nonce

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
Fonctionnement d'une CSP stricte basée sur des nonce

CSP stricte basée sur le hachage

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

Les propriétés suivantes rendent une CSP comme celle-ci "stricte" et donc sécurisés:

  • Elle utilise des nonces 'nonce-{RANDOM}' ou des hachages 'sha256-{HASHED_INLINE_SCRIPT}'. pour indiquer les balises <script> dans lesquelles le développeur du site fait confiance pour s'exécuter dans le navigateur de l'utilisateur.
  • Elle définit 'strict-dynamic'. pour réduire le travail de déploiement d'un CSP basé sur des nonces ou des hachages en permettant l’exécution de scripts créés par un script de confiance. De plus, débloque l'utilisation de la plupart des widgets et bibliothèques JavaScript tiers.
  • Il n'est pas basé sur les listes d'autorisation d'URL. Il ne souffre donc pas contournements courants de CSP.
  • Il bloque les scripts intégrés non fiables tels que les gestionnaires d'événements intégrés ou javascript:. URI.
  • Elle limite object-src pour désactiver les plug-ins dangereux tels que Flash.
  • Elle limite base-uri pour bloquer l'injection des balises <base>. Cela permet d'éviter les attaquants de modifier l’emplacement des scripts chargés à partir d’URL relatives.

Adopter une CSP stricte

Pour adopter une CSP stricte, vous devez:

  1. Déterminez si votre application doit définir un CSP basé sur des nonce ou un hachage.
  2. Copiez la CSP depuis la section Structure de CSP stricte et configurez-la en tant qu'en-tête de réponse dans votre application.
  3. Refactoriser les modèles HTML et le code côté client pour supprimer les modèles incompatible avec CSP.
  4. Déployez votre CSP.

Vous pouvez utiliser Lighthouse (version 7.3.0 ou ultérieure avec l'option --preset=experimental) Audit des bonnes pratiques tout au long du processus pour vérifier si votre site dispose d'une CSP, suffisamment stricte pour être efficace contre les scripts intersites.

Phare
  signaler un avertissement indiquant qu&#39;aucune CSP n&#39;est détectée en mode application forcée.
Si votre site n'a pas de CSP, Lighthouse affiche cet avertissement.

Étape 1: Déterminez si vous avez besoin d'une CSP basée sur un nonce ou un hachage

Voici comment fonctionnent les deux types de CSP strictes:

CSP basée sur le nonce

Avec un CSP basé sur des nonce, vous générez un nombre aléatoire au moment de l'exécution et vous l'incluez dans votre CSP et l'associer à chaque balise de script de votre page. Un pirate informatique ne peuvent pas inclure ni exécuter un script malveillant sur votre page, car ils auraient besoin deviner le nombre aléatoire correct pour ce script. Cela ne fonctionne que si le nombre n'est pas devinable et est généré lors de l'exécution pour chaque réponse.

Utilisez une CSP basée sur des nonce pour les pages HTML affichées sur le serveur. Pour ces pages, vous pouvez créer un nouveau nombre aléatoire pour chaque réponse.

CSP basée sur le hachage

Dans le cas d'une CSP basée sur un hachage, le hachage de chaque tag de script intégré est ajouté à la CSP. Chaque script est associé à un hachage différent. Un attaquant ne peut pas inclure ou exécuter dans votre page, car le hachage de ce script devrait se trouver CSP pour l'exécution.

Utilisez un CSP basé sur le hachage pour les pages HTML diffusées en mode statique ou les pages qui doivent être mis en cache. Par exemple, vous pouvez utiliser une CSP basée sur un hachage pour le Web monopage. des applications créées avec des frameworks comme Angular, React ou d'autres, qui sont diffusées de manière statique sans affichage côté serveur.

Étape 2: Définissez une CSP stricte et préparez vos scripts

Lorsque vous configurez une CSP, vous disposez de plusieurs options:

  • Mode Rapport uniquement (Content-Security-Policy-Report-Only) ou mode application forcée (Content-Security-Policy). En mode rapport uniquement, la CSP ne bloque de ressources. Ainsi, votre site ne tombera jamais en panne, mais vous pourrez voir les erreurs des rapports sur tous les éléments qui auraient été bloqués. Au niveau local, lorsque vous dans la configuration de votre CSP, cela n'a pas vraiment d'importance, car les deux modes vous indiquent dans la console du navigateur. Le mode application forcée peut vous aider à trouver ressources que votre brouillon de bloc CSP peut avoir, car le blocage d'une ressource peut la page semble défectueuse. Le mode Rapport uniquement devient plus utile plus tard dans le processus (voir l'étape 5).
  • En-tête ou balise HTML <meta>. Pour le développement local, un tag <meta> peut être plus pratique pour ajuster votre CSP et voir rapidement son impact sur votre site. Toutefois:
    • Par la suite, lors du déploiement de votre CSP en production, nous vous recommandons de le définir un en-tête HTTP.
    • Si vous souhaitez définir votre CSP en mode "Rapport uniquement", vous devez le définir en tant que car les balises Meta CSP ne sont pas compatibles avec le mode rapport uniquement.

Option A: CSP basée sur le nonce

Définissez la réponse HTTP Content-Security-Policy suivante dans votre application:

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

Générer un nonce pour CSP

Un nonce est un nombre aléatoire utilisé une seule fois par chargement de page. Un nonce CSP ne peut atténuer les failles XSS que si les pirates informatiques ne peuvent pas deviner la valeur du nonce. A Le nonce CSP doit être:

  • Une valeur aléatoire cryptographiquement forte (dans l'idéal, d'une longueur de plus de 128 bits)
  • Générées pour chaque réponse
  • Encodage en base64

Voici quelques exemples d'ajout d'un nonce CSP dans les frameworks côté serveur:

const app = express();

app.get('/', function(request, response) {
  // Generate a new random nonce value for every response.
  const nonce = crypto.randomBytes(16).toString("base64");

  // Set the strict nonce-based CSP response header
  const csp = `script-src 'nonce-${nonce}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`;
  response.set("Content-Security-Policy", csp);

  // Every <script> tag in your application should set the `nonce` attribute to this value.
  response.render(template, { nonce: nonce });
});

Ajouter un attribut nonce aux éléments <script>

Avec une CSP basée sur des nonce, chaque élément <script> doit comportent un attribut nonce qui correspond au nonce aléatoire spécifiée dans l'en-tête CSP. Tous les scripts peuvent avoir le même nonce La première étape consiste à ajouter ces attributs à tous les scripts afin que CSP les autorise.

Option B: En-tête de réponse CSP basée sur un hachage

Définissez la réponse HTTP Content-Security-Policy suivante dans votre application:

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

Pour plusieurs scripts intégrés, la syntaxe est la suivante: 'sha256-{HASHED_INLINE_SCRIPT_1}' 'sha256-{HASHED_INLINE_SCRIPT_2}'

Charger dynamiquement des scripts issus d'une source

Étant donné que les hachages CSP sont compatibles avec les navigateurs uniquement pour les scripts intégrés, vous devez charger tous les scripts tiers de manière dynamique à l'aide d'un script intégré. Le hachage des scripts source n'est pas compatible avec tous les navigateurs.

Exemple d'intégration de vos scripts
Autorisé par CSP
<script>
  var scripts = [ 'https://example.org/foo.js', 'https://example.org/bar.js'];

  scripts.forEach(function(scriptUrl) {
    var s = document.createElement('script');
    s.src = scriptUrl;
    s.async = false; // to preserve execution order
    document.head.appendChild(s);
  });
</script>
Pour permettre à ce script de s'exécuter, vous devez calculer le hachage du script intégré et ajoutez-le à l'en-tête de réponse CSP, en remplaçant {HASHED_INLINE_SCRIPT} . Pour réduire le nombre de hachages, vous pouvez fusionner scripts en un seul script. Pour voir comment cela fonctionne, consultez exemple et son code.
Bloqué par CSP
<script src="https://example.org/foo.js"></script>
<script src="https://example.org/bar.js"></script>
CSP bloque ces scripts, car seuls les scripts intégrés peuvent être hachés.

Remarques concernant le chargement du script

L'exemple de script intégré ajoute s.async = false pour garantir que foo exécute avant bar, même si bar se charge en premier. Dans cet extrait, s.async = false ne bloque pas l'analyseur pendant le chargement des scripts, car les scripts sont ajoutés de manière dynamique. L'analyseur s'arrête uniquement pendant l'exécution des scripts, c'est le cas pour async scripts. Toutefois, avec cet extrait, Gardez à l'esprit les points suivants:

  • L'un des scripts ou les deux peuvent s'exécuter avant la fin du document en cours de téléchargement. Si vous souhaitez que le document soit prêt au moment scripts s'exécutent, attendez l'événement DOMContentLoaded avant de vous ajoutez les scripts. Si cela entraîne un problème de performances le téléchargement des scripts ne commence pas assez tôt, utilisez des balises de préchargement plus tôt sur la page.
  • defer = true n'a aucun effet. Si vous en avez besoin, , exécutez le script manuellement si nécessaire.

Étape 3: Refactoriser les modèles HTML et le code côté client

Gestionnaires d'événements intégrés (tels que > et >) et URI JavaScript (<a href="javascript:…">) permet d'exécuter des scripts. Cela signifie qu'un un pirate informatique qui trouve un bug XSS peut injecter ce type de code HTML et exécuter des JavaScript. Une CSP basée sur des nonce ou un hachage interdit l'utilisation de ce type de balisage. Si votre site utilise l'un de ces formats, vous devrez les refactoriser pour qu'ils soient plus sûrs alternatives.

Si vous avez activé CSP à l'étape précédente, vous pourrez voir les cas de non-respect CSP dans la console chaque fois que CSP bloque un schéma incompatible.

Signalements de non-respect CSP dans la console pour les développeurs Chrome.
Erreurs de la console pour du code bloqué.

Dans la plupart des cas, la solution est simple:

Refactoriser les gestionnaires d'événements intégrés

Autorisé par CSP
<span id="things">A thing.</span>
<script nonce="${nonce}">
  document.getElementById('things').addEventListener('click', doThings);
</script>
CSP autorise les gestionnaires d'événements enregistrés à l'aide de JavaScript.
Bloqué par CSP
<span >A thing.</span>
CSP bloque les gestionnaires d'événements intégrés.

Refactoriser les URI javascript:

Autorisé par CSP
<a id="foo">foo</a>
<script nonce="${nonce}">
  document.getElementById('foo').addEventListener('click', linkClicked);
</script>
CSP autorise les gestionnaires d'événements enregistrés à l'aide de JavaScript.
Bloqué par CSP
<a href="javascript:linkClicked()">foo</a>
CSP bloque les URI JavaScript.

Supprimer eval() de votre code JavaScript

Si votre application utilise eval() pour convertir les sérialisations de chaînes JSON en JavaScript , vous devez refactoriser ces instances vers JSON.parse(), qui est également plus vite.

Si vous ne pouvez pas supprimer toutes les utilisations de eval(), vous pouvez toujours définir une valeur stricte basée sur des nonces CSP, mais vous devez utiliser le mot clé CSP 'unsafe-eval', ce qui rend votre est un peu moins sécurisée.

Vous trouverez ces exemples et d'autres exemples de refactorisation dans cette CSP stricte codelab:

Étape 4 (facultative): Ajoutez des créations de remplacement pour assurer la compatibilité avec les anciennes versions de navigateur

Navigateurs pris en charge

  • Chrome: 52
  • Edge: 79
  • Firefox: 52
  • Safari: 15.4.

Source

Si vous devez assurer la compatibilité avec d'anciennes versions de navigateur:

  • L'utilisation de strict-dynamic nécessite l'ajout de https: en remplacement pour une version antérieure. de Safari. Lorsque vous procédez ainsi:
    • Tous les navigateurs compatibles avec strict-dynamic ignorent la création de remplacement https:. donc cela ne réduira pas la force de la règle.
    • Dans les anciens navigateurs, les scripts externes ne peuvent être chargés que s'ils proviennent une origine HTTPS. Cette méthode est moins sécurisée qu'une CSP stricte, mais elle empêche certaines causes XSS courantes telles que les injections d'URI javascript:.
  • Pour assurer la compatibilité avec les très anciennes versions de navigateur (4 ans et plus), vous pouvez ajouter unsafe-inline en remplacement. Tous les navigateurs récents ignorent unsafe-inline si un nonce ou un hachage CSP est présent.
Content-Security-Policy:
  script-src 'nonce-{random}' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';

Étape 5: Déployez votre CSP

Après avoir vérifié que votre CSP ne bloque pas les scripts légitimes dans votre environnement de développement local, vous pouvez déployer votre CSP en préproduction, de production:

  1. (Facultatif) Déployez votre CSP en mode rapport uniquement à l'aide de En-tête Content-Security-Policy-Report-Only. Le mode Rapport uniquement est pratique pour tester une modification potentiellement destructive comme un nouveau fournisseur de services cloud en production commencer à appliquer des restrictions liées aux CSP. En mode rapport uniquement, votre CSP ne affectent le comportement de votre application, mais le navigateur génère quand même des erreurs dans la console. et les signalements de violations lorsqu'il rencontre des formats incompatibles avec votre CSP, afin que vous puissiez voir ce qui n'aurait pas fonctionné pour vos utilisateurs finaux. Pour plus consultez API Reporting.
  2. Si vous êtes sûr que votre CSP ne perturbera pas votre site pour les utilisateurs finaux, Déployez votre CSP à l'aide de l'en-tête de réponse Content-Security-Policy. Mer nous vous recommandons de définir votre CSP à l'aide d'un en-tête HTTP côté serveur, car il est plus qu'un tag <meta>. Une fois cette étape terminée, votre CSP commence protéger votre application contre les attaques XSS.

Limites

Une CSP stricte fournit généralement un niveau de sécurité supplémentaire élevé qui aide à pour atténuer les effets de XSS. Dans la plupart des cas, CSP réduit considérablement la surface d'attaque, rejetant les modèles dangereux tels que les URI javascript:. Toutefois, en fonction du type de CSP que vous utilisez (nonces, hachages, avec ou sans 'strict-dynamic'), il y a CSP ne protège pas votre application également:

  • Si vous créez un nonce de script, mais qu'il y a une injection directement dans le corps ou Paramètre src de cet élément <script>.
  • S'il y a des injections aux emplacements des scripts créés dynamiquement (document.createElement('script')), y compris dans les fonctions de la bibliothèque qui créent script nœuds DOM en fonction des valeurs de leurs arguments. Ce comprend des API courantes telles que .html() de jQuery, ainsi que .get() et .post() dans jQuery < 3.0.
  • S'il existe des injections de modèles dans d'anciennes applications AngularJS Un pirate informatique injectable dans un modèle AngularJS, peut l'utiliser pour exécuter du code JavaScript arbitraire.
  • Si la règle contient 'unsafe-eval', des injections dans eval(), setTimeout() et quelques autres API rarement utilisées.

Les développeurs et les ingénieurs en sécurité doivent accorder une attention particulière des schémas lors des revues de code et des audits de sécurité. Vous trouverez plus d'informations sur ces cas dans l'article Content Security Policy: A Réussit entre la sécurisation renforcée et son atténuation.

Documentation complémentaire