Tous les articles

Le schéma data dans la Content Security Policy

CentralCSP Team ·

Dernière mise à jour:

Le schéma data: permet à une URL de transporter son propre contenu en inline, si bien que data:image/png;base64,... constitue une image entière sans serveur à interroger. Dans une politique de sécurité du contenu (CSP), vous pouvez autoriser ce schéma directive par directive. Pour les images et les polices, c'est pratique et courant. Pour les scripts, cela offre à un attaquant un moyen d'exécuter du code sans aucun hôte externe.

Cet article montre où data: a sa place dans une politique, où il n'en a pas, et pourquoi la différence compte.

À quoi ressemble le schéma data dans une CSP

data: est une source de schéma. La grammaire correspond au nom du schéma suivi de deux-points, donc vous écrivez data: tel quel, avec le deux-points final et sans guillemets, contrairement aux sources par mot-clé comme 'self'.

L'usage courant et raisonnable concerne les images et les polices en inline :

Content-Security-Policy: img-src 'self' data:; font-src 'self' data:

Cela autorise img-src et font-src à charger des ressources depuis votre propre origine et depuis des data URI en inline, ce qui permet l'affichage des icônes en base64, des petites images de remplacement et des polices embarquées.

Chaque directive est indépendante. Il n'y a pas de data: sur une directive tant que vous ne l'y écrivez pas, et il n'arrive ni par un fallback ni par un wildcard (nous y revenons plus bas).

Pourquoi data est sûr pour les images mais dangereux pour les scripts

Une image data: ne peut pas exécuter de code. Ce sont des octets que le navigateur décode et peint. Un script data: est différent : l'URL transporte le corps du script, donc toute la charge utile voyage à l'intérieur de l'expression de source.

Si script-src autorise ce schéma, un attaquant capable d'injecter une seule balise <script> n'a besoin d'héberger quoi que ce soit. Le code passe directement dans l'URL :

<script src="data:text/javascript,alert(document.domain)"></script>
<script src="data:;base64,YWxlcnQoMSk="></script>

Les versions actuelles de Chrome, Firefox et Safari exécutent les scripts data: externes, donc c'est un vecteur d'exécution opérationnel aujourd'hui, pas une bizarrerie héritée du passé. Les analyses de risque présentent data: dans script-src comme un contournement de CSP ; la spécification CSP elle-même ne définit que la correspondance des schémas et ne le signale pas comme un avertissement XSS, donc traitez ce danger comme un constat de durcissement plutôt que comme une règle de la spec.

Une distinction maintient l'honnêteté du propos. Les navigateurs bloquent la navigation de premier niveau vers une URL data:, un changement anti-phishing plus ancien, mais cela ne bloque pas les sous-ressources data: comme <script src="data:..."> ou <img src="data:...">. Le script se charge en sous-ressource dans la propre origine de la page, donc le blocage de navigation ne s'applique pas.

Le wildcard ne couvre pas data

On suppose naturellement que script-src * autorise tout, y compris data:. Ce n'est pas le cas. En CSP Level 3, un simple * ne correspond à une URL que lorsque celle-ci utilise un schéma HTTP ou HTTPS (plus le même schéma que le document protégé). Les schémas data:, blob: et filesystem: sont exclus et doivent être listés explicitement.

Content-Security-Policy: script-src *

Cette politique n'autorise pas les scripts data:. Il faudrait ajouter data: vous-même pour qu'ils s'exécutent, ce qui est précisément la raison pour laquelle vous ne devriez pas le faire.

Cette exclusion est un correctif de sécurité délibéré. Les navigateurs ont plus tard restreint la correspondance de data: après qu'un contournement réel via un wildcard s'est confirmé, et le comportement est cohérent entre les navigateurs actuels.

Où autoriser data, et où ne pas le faire

Décidez directive par directive, selon que la directive peut ou non mener à l'exécution de code :

  • img-src, font-src et media-src : autoriser data: est légitime et très répandu pour les ressources en base64 en inline.
  • script-src : n'autorisez pas data:. C'est un vecteur d'exécution XSS, comme montré plus haut.
  • object-src et frame-src : risqués également, puisque des plugins ou des frames data: peuvent transporter du contenu actif.
  • style-src : déconseillé. Une feuille de style data: contrôlée par un attaquant se charge comme une sous-ressource et s'applique, ce qui constitue un vrai vecteur d'injection et d'exfiltration basé sur CSS (mais pas d'exécution de code).
  • default-src : particulièrement néfaste. En l'absence de script-src, c'est default-src qui régit les scripts, donc default-src data: permet de fait les scripts data:.

Une grande partie des sites autorisait historiquement data: sous script-src, frame-src ou object-src (ou default-src lorsque script-src était absent), et c'est pourquoi cela reste un constat fréquent.

L'alternative plus sûre pour les scripts

Le correctif n'est pas de trouver une manière prudente d'autoriser data: dans script-src. C'est de cesser complètement d'autoriser les scripts par schéma ou par hôte, et de les autoriser par nonce ou hash à la place, avec 'strict-dynamic'.

Les recommandations de Chrome et de Google sont explicites : les allowlists par hôte et par schéma offrent peu de protection, et un nonce ou un hash plus 'strict-dynamic' est le modèle à adopter. Une politique stricte minimale ressemble à ceci :

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

Avec un nonce en place, le navigateur ne fait confiance qu'aux scripts portant ce nonce et aux scripts que ces scripts de confiance chargent. Un script data: sans nonce correspondant est rejeté, donc le contournement se referme même si un attaquant injecte une balise. Pour l'argumentaire plus large contre l'ouverture de la politique de cette façon, voyez pourquoi supprimer 'unsafe-inline' compte et la démonstration plus complète dans comment construire une CSP solide.

Si vous avez besoin de quelques images ou polices en base64 en inline, gardez data: cantonné à img-src et font-src et laissez-le hors de tout ce qui touche au script ou au style.

Repérer data dans votre propre politique

Déployez les changements de la manière sûre : placez d'abord une politique candidate sur le header Content-Security-Policy-Report-Only, surveillez les reports, et n'appliquez la politique qu'une fois qu'ils sont silencieux. Pour voir où en est votre politique en production aujourd'hui, passez-la dans le évaluateur CSP, qui signale data: dans script-src et d'autres sources faibles afin que vous sachiez quoi resserrer avant qu'elles ne deviennent une porte d'entrée.

L'évaluateur lit la politique que vous livrez déjà. Ce qu'il ne peut pas vous dire, c'est quelles URI data: vos pages chargent réellement, car cela n'apparaît qu'à l'exécution. CentralCSP collecte les reports csp-violation issus de vraies visites et les regroupe par URI bloquée, si bien qu'en retirant data: de script-src vous voyez exactement quels payloads inline cessent de se charger, et si certains étaient les vôtres.

Articles liés