SaaSFort
CSP en-têtes de sécurité Trusted Types XSS OWASP modèle de maturité

Un modèle de maturité CSP : cinq niveaux, et où la plupart des SaaS s'arrêtent

Presque tous les SaaS ont une Content-Security-Policy. Presque aucun ne dépasse le niveau deux. Voici l'échelle et ce que chaque barreau vous apporte réellement.

ST
SaaSFort Team
· 5 min de lecture

Content-Security-Policy est l’en-tête le plus puissant que le navigateur vous offre, et celui le plus souvent déployé sous une forme qui ne protège presque rien.

La raison est que « possède une CSP » est binaire dans un questionnaire et continu dans la réalité. Voici l’échelle, ce que chaque niveau arrête, et où se situe le décrochage.

Niveau 0 : aucune CSP

Aucune politique. Tout script injecté s’exécute.

Plus fréquent qu’on ne l’imagine sur les sous-domaines applicatifs authentifiés, parce que le site marketing a eu la revue de sécurité et app. non.

Niveau 1 : une CSP contenant unsafe-inline

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'

C’est le niveau que la plupart des déploiements atteignent et où ils restent. Il passe un contrôle de présence d’en-tête et n’arrête pour ainsi dire rien, car unsafe-inline autorise n’importe quel script en ligne, ce qui est précisément ce que produit une injection.

Si votre politique contient unsafe-inline dans script-src, vous êtes au niveau 1 quelle que soit la longueur du reste de l’en-tête. Traitez la présence de ce mot-clé comme la chose la plus importante à trouver et à supprimer.

Niveau 2 : une liste blanche sans unsafe-inline

Content-Security-Policy: script-src 'self' https://cdn.example.com https://analytics.example.com

Une vraie protection contre le script en ligne trivialement injecté. Deux problèmes structurels.

La liste blanche grossit. Chaque nouveau prestataire ajoute un domaine, et personne n’en retire, donc elle dérive vers l’autorisation de la moitié d’Internet.

Les listes blanches sont contournables par leurs propres entrées. Un CDN autorisé qui héberge du contenu utilisateur arbitraire, ou un domaine permis servant un point d’entrée JSONP ou un framework obsolète avec un gadget connu, devient un chemin d’exécution. C’est bien documenté, et c’est pourquoi les politiques à liste blanche ne sont plus la recommandation.

Niveau 3 : nonce plus strict-dynamic

Content-Security-Policy:
  script-src 'nonce-{aléa}' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none'; base-uri 'self'

La forme recommandée aujourd’hui. Chaque réponse porte un nonce frais ; seuls les scripts qui le portent s’exécutent. strict-dynamic laisse ces scripts de confiance charger leurs propres dépendances sans maintenir une liste de domaines, ce qui fait cesser la croissance de la politique.

Les https: et 'unsafe-inline' finaux sont des replis délibérés pour les navigateurs anciens qui ne comprennent pas strict-dynamic. Ceux qui le comprennent les ignorent. Cela paraît alarmant en revue et c’est correct.

Les directives d’appui comptent à ce niveau :

  • object-src 'none' supprime les chemins d’exécution par plugins.
  • base-uri 'self' empêche une injection de <base> de détourner toutes les URL relatives de la page.
  • frame-ancestors 'none' traite le clickjacking plus finement que X-Frame-Options.

Atteindre le niveau 3 demande un nonce dans votre couche de gabarits, ce qui représente un vrai travail sur une application ancienne. C’est l’étape la plus rentable de cette échelle.

Niveau 4 : Trusted Types

  require-trusted-types-for 'script';
  trusted-types sanitizer default;

Les niveaux 1 à 3 contrôlent d’où viennent les scripts. Aucun ne traite le DOM XSS, où aucun script n’est chargé : une chaîne à laquelle l’application fait déjà confiance est passée à innerHTML ou un équivalent et devient du code.

Trusted Types fait refuser les chaînes à ces points d’injection. Le seul moyen d’y écrire passe par une politique nommée que vous avez déclarée, ce qui transforme « les quatre cents affectations sont-elles sûres » en « ces trois politiques sont-elles correctes ».

Les deux directives comptent. require-trusted-types-for active l’application ; trusted-types fixe l’ensemble des politiques créables, donc un script tiers compromis ne peut pas fabriquer la sienne. L’application sans la liste blanche est un déploiement partiel.

Le chemin de déploiement complet, mode report-only compris.

Niveau 5 : la remontée, et la couche d’intégrité à côté

Une politique sans remontée est une politique que vous ne pouvez pas maintenir, car les violations sont silencieuses et vous apprenez les casses par vos utilisateurs.

  report-to csp-endpoint;
Reporting-Endpoints: csp-endpoint="https://example.com/_reports/csp"

Utilisez report-to avec un en-tête Reporting-Endpoints. report-uri est déprécié, quoique encore largement honoré, donc envoyer les deux pendant la transition est raisonnable.

À ce niveau, il vaut aussi la peine de nommer ce que la CSP ne peut structurellement pas faire : elle ne protège pas des vulnérabilités côté serveur, et elle ne protège pas d’une compromission de la chaîne d’approvisionnement d’une source de scripts que vous autorisez déjà. Le script arrive d’une origine permise avec un nonce valide, et la CSP n’a aucune opinion sur son contenu. Ce trou est couvert par Subresource Integrity et son en-tête d’application, par aucune directive CSP.

L’échelle en un coup d’œil

NiveauFormeArrête
0Aucun en-têteRien
1unsafe-inline présentEn pratique rien
2Liste blancheL’injection naïve ; contournable via les origines permises
3Nonce + strict-dynamicL’exécution de script injecté
4+ Trusted TypesLe DOM XSS au point d’injection
5+ remontée, + application SRILa dérive et l’altération par un tiers

Trouver votre niveau en une commande

curl -sI https://votredomaine.fr | grep -i content-security-policy

Puis, dans l’ordre : unsafe-inline est-il dans script-src ? Y a-t-il un nonce ? strict-dynamic est-il présent ? require-trusted-types-for est-il présent ? Y a-t-il un point de collecte ?

Vérifiez votre sous-domaine applicatif séparément de votre site marketing. Ils sont souvent à des niveaux différents, et celui qui détient les données clients est fréquemment le plus bas des deux.

En résumé

La présence de l’en-tête n’est pas un contrôle. unsafe-inline dans script-src vous place au niveau 1 quoi que dise le reste de la politique.

Le niveau 3 est l’étape la plus rentable. Le niveau 4 traite une classe d’attaque entière que les trois premiers n’effleurent pas.

Partager cet article
LinkedIn Post

Passez de la lecture à l'action

Scannez votre domaine gratuitement. Premiers résultats en moins de 10 secondes — sans inscription.

Scanner gratuitement

Continuer la lecture