Garantir l'efficacité de CSP contre les attaques XSS

Une CSP (Content Security Policy) permet de s'assurer que le contenu chargé sur la page est approuvé par le propriétaire du site. Les CSP réduisent les attaques par script intersites (XSS), car elles peuvent bloquer les scripts non sécurisés 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ées au document principal et signale les problèmes à CSP Evaluator s'ils peuvent être contournés.

Avertissement du rapport Lighthouse indiquant qu'aucune CSP n'a été détectée en mode application forcée.
Le rapport Lighthouse indique qu'aucune CSP n'a été détectée en mode application forcée.

Pratiques requises pour une CSP non contournable

Mettez en œuvre les pratiques suivantes pour vous assurer que votre CSP ne peut pas être contourné. Si la CSP peut être contournée, Lighthouse émet un avertissement de gravité élevée.

CSP cible XSS

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

script-src et object-src sécurisent une page contre les scripts et les plug-ins non sécurisés. Vous pouvez également utiliser default-src pour configurer une stratégie globale à la place de nombreuses instructions, 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 le pirate informatique.

CSP utilise des nonces ou des hachages pour éviter les contournements de la liste d'autorisation

Un CSP qui configure une liste d'autorisation pour script-src repose sur l'hypothèse que toutes les réponses provenant d'un domaine de confiance 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 neutres courants, tels que l'exposition des interfaces JSONP et l'hébergement de copies de la bibliothèque AngularJS, permettent aux pirates informatiques de s'échapper de l'intérieur de CSP.

En pratique, même si les auteurs d'applications ne le disent pas nécessairement, la majorité des listes d'autorisation script-src peuvent être contournées par un pirate informatique présentant un bug XSS et n'offrent que peu de protection contre l'injection de scripts. En revanche, les approches basées sur des nonces et sur le hachage ne souffrent pas de ces problèmes, et facilitent l'adoption et le maintien d'une stratégie plus sécurisée.

Par exemple, ce code utilise un point de terminaison JSONP hébergé sur un domaine de confiance 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é, une 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

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

Configurer les rapports CSP

En configurant une destination de reporting, vous pouvez surveiller les éventuels problèmes. Vous pouvez définir la destination du rapport à l'aide des instructions report-uri ou report-to. report-to n'est pas compatible avec tous les navigateurs récents. Nous vous recommandons donc d'utiliser les deux ou simplement report-uri.

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

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

Une CSP peut être définie dans une balise Meta de la manière suivante:

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

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

Assurez-vous que CSP est rétrocompatible

Tous les navigateurs ne sont pas compatibles avec les nonces/hachages CSP. Il est donc recommandé d'ajouter unsafe-inline comme solution de remplacement pour les navigateurs non conformes. Si le navigateur prend en charge 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 en tant que 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'une CSP stricte avec une règle basée sur des nonces.

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 une CSP stricte.

Vous pouvez vérifier si une CSP a recours à des contournements potentiels à l'aide de Lighthouse et de CSP Evaluator. Si vous souhaitez tester une nouvelle CSP sans risquer de perturber 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 CSP seront envoyés à toutes les destinations de reporting que vous avez configurées avec report-to et report-uri. Toutefois, cela n'appliquera pas la CSP.