Garantir l'efficacité de CSP contre les attaques XSS

Une CSP (Content Security Policy) permet de s'assurer que tout contenu chargé sur la page est approuvé par le propriétaire du site. Les CSP atténuent les attaques par script intersites (XSS), car ils peuvent bloquer les scripts dangereux injectés par des pirates informatiques. Cependant, la CSP peut facilement être contournée si elle n'est pas assez stricte. Pour en savoir plus, consultez Limiter les scripts intersites (XSS) avec une CSP (Content Security Policy) stricte. Lighthouse collecte les CSP appliqués au document principal et signale les problèmes détectés par l'évaluateur de CSE s'ils peuvent être contournés.

Avertissement du rapport Lighthouse indiquant qu'aucun CSP n'est détecté en mode de mise en conformité.
Un rapport Lighthouse signale qu'aucune CSP n'a été détectée en mode application forcée.

Pratiques requises pour une CSP non contournable

Implémentez les pratiques suivantes pour vous assurer que votre CSP ne peut pas être contourné. Si le CSP peut être contourné, Lighthouse émet un avertissement de gravité élevée.

XSS cibles du CSP

Pour cibler les attaques XSS, un CSP doit inclure les directives script-src, object-src et base-uri. Le CSP doit également être exempt d'erreurs de syntaxe.

script-src et object-src protègent respectivement une page contre les scripts et les plug-ins non sécurisés. Vous pouvez également utiliser default-src pour configurer une règle large à la place de nombreuses directives, y compris script-src et object-src.

base-uri empêche l'injection de balises <base> non autorisées, qui peuvent être utilisées pour rediriger toutes les URL relatives (comme les scripts) vers un domaine contrôlé par un pirate informatique.

Le CSP utilise des nonces ou des hachages pour éviter les détournements de liste d'autorisation

Un fournisseur de services cloud qui configure une liste d'autorisation pour script-src part du principe que toutes les réponses provenant d'un domaine approuvé sont sûres et peuvent être exécutées en tant que scripts. Cependant, cette hypothèse ne s'applique pas aux applications modernes. Certains modèles courants et inoffensifs, tels que l'exposition d'interfaces JSONP et l'hébergement de copies de la bibliothèque AngularJS, permettent aux pirates informatiques d'échapper aux limites du CSP.

En pratique, bien que cela ne soit pas évident pour les auteurs d'applications, la majorité des listes d'autorisation script-src peuvent être contournées par un pirate informatique disposant d'un bug XSS et offrent peu de protection contre l'injection de script. En revanche, les approches basées sur les nonce et sur le hachage ne souffrent pas de ces problèmes. Elles facilitent l'adoption et le maintien d'une règle plus sécurisée.

Par exemple, ce code utilise un point de terminaison JSONP hébergé sur un domaine approuvé pour injecter un script contrôlé par un pirate informatique:

CSP :

script-src https://trusted.example.com

HTML :

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

Pour éviter d'être contourné, un CSP doit autoriser les scripts individuellement à l'aide de nonces ou de hachages, et utiliser "strict-dynamic" au lieu d'une liste d'autorisation.

Recommandations supplémentaires pour une CSP sécurisée

Implémentez les pratiques suivantes pour renforcer la sécurité et la compatibilité. Si le CSP ne suit pas l'une des recommandations, Lighthouse émet un avertissement de gravité moyenne.

Configurer les rapports CSP

Configurer une destination de création de rapports vous aidera à surveiller les pannes. Vous pouvez définir la destination des rapports à l'aide des instructions report-uri ou report-to. report-to n'est actuellement pas compatible avec tous les navigateurs modernes. Il est donc recommandé d'utiliser les deux ou uniquement report-uri.

Si un contenu ne respecte pas le CSP, le navigateur envoie un rapport à la destination configurée. Assurez-vous qu'une application est configurée à cette destination pour gérer ces rapports.

Définir la CSP dans un en-tête HTTP

Une CSP peut être définie dans une balise méta comme suit :

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

Toutefois, vous devez, si possible, définir une CSP dans un en-tête de réponse HTTP. Une injection avant la balise méta contourne le CSP. De plus, frame-ancestors, sandbox et la création de rapports ne sont pas compatibles avec les CSP de balise Meta.

Assurez-vous que CSP est rétrocompatible

Tous les navigateurs ne prennent pas en charge les nonces/hachages CSP. Il est donc recommandé d'ajouter unsafe-inline comme solution de secours pour les navigateurs non conformes. Si le navigateur est compatible avec les nonces/hachages, unsafe-inline sera ignoré.

De même, strict-dynamic n'est pas compatible avec tous les navigateurs. Nous vous recommandons de définir une liste d'autorisation comme solution de remplacement pour tous les navigateurs non conformes. La liste d'autorisation sera ignorée dans les navigateurs compatibles avec strict-dynamic.

Développer une CSP stricte

Vous trouverez ci-dessous un exemple d'utilisation d'un CSP strict avec une règle basée sur un nonce.

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML :

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 correspond à n'importe quelle chaîne base64 générée côté serveur à chaque chargement de la page. unsafe-inline et https: sont ignorés dans les navigateurs modernes en raison du nonce et de strict-dynamic. Pour en savoir plus sur l'adoption d'une CSP stricte, consultez le guide sur les CSP strictes.

Vous pouvez vérifier si un CSE présente des échappatoires potentielles à l'aide de Lighthouse et de CSP Evaluator. Si vous souhaitez tester une nouvelle CSP sans risquer d'endommager les pages existantes, définissez-la en mode rapport uniquement en utilisant Content-Security-Policy-Report-Only comme nom d'en-tête. Les cas de non-respect de la CSP seront envoyés à toutes les destinations de rapports que vous avez configurées avec report-to et report-uri, mais la CSP ne sera pas réellement appliquée.