Content Security Policy : les prochains Firefox seront mieux protégés contre les XSS
Par Clochix le dimanche 4 octobre 2009, 00:31 - Lézarderies - Lien permanent
Brandon Sterne, qui travaille sur la sécurité de Firefox, vient d'annoncer que des versions de développement de Firefox intégrant la spécification Content Security Policy sont disponibles depuis quelques jours. Cette spécification est une proposition de Mozilla pour renforcer la sécurité des navigateurs contre les attaques de type XSS.
XSS
Les attaques XSS, ou Cross Site Scripting sont parmi les plus courantes sur le réseau. Elles consistent à faire s'exécuter un script, généralement JavaScript, par le navigateur. Imaginons pas exemple un blog qui autoriserait le HTML dans les commentaires sans filtrer les saisies. On pourrait ainsi insérer des scripts dans les commentaires. Ces scripts s'exécuteraient dans le navigateur de toute personne consultant le commentaire comme s'ils étaient des scripts légitimes de l'application. A partir de là, tout est possible, le script peut effectuer toutes les opérations autorisées à l'utilisateur. Si l'administrateur du blog consulte un commentaire piégé, le script pourra par exemple effacer les billets, modifier les droits d'accès au blog, etc. Le jeu pour les auteurs de ce type de script consiste à contourner les protections mises en place au niveau serveur pour réussir à insérer du code qui s'affichera et s'exécutera dans le navigateur des utilisateurs. Par exemple en cachant le code dans l'URL d'une image ou d'un lien. Ces attaques utilisent le fait que le navigateur fait confiance par défaut à tout le contenu en provenance du site Web.
Content Security Policy
Pour y remédier, CSP propose une approche basée sur le principe d'une liste blanche : le site liste explicitement les contenus légitimes. Si un site indique qu'il utilise CSP, le navigateur ne fera donc confiance qu'aux scripts contenus dans cette liste blanche et refusera d'exécuter les autres.
CSP a en fait une double fonction:
- il essaie de prévenir l'exécution de code non désiré, et protège donc les utilisateurs;
- lorsqu'il détecte une tentative de violation des politiques de sécurité, il en informe le site. Les responsables de celui-ci peuvent donc être rapidement prévenus de toute tentative d'attaque contre leur site, et prendre les mesures pour la bloquer;
Un site indique au navigateur qu'il implémente CSP via l'entête HTTP
X-Content-Security-Policy. Celui-ci peut soit contenir la
description de la politique, soit l'URI d'un document la décrivant.
Les politiques ne s'appliquent bien sûr qu'aux contenus chargés depuis un site distant, pas aux extensions ou aux scripts locaux de l'utilisateur (type bookmarklets).
Un prototype de CSP a d'abord été implémentée sous forme d'une extension, avant d'intégrer récemment le cœur de Firefox. Les politiques de sécurité seront donc disponibles dans une des prochaines versions du navigateur, la 3.6 ou la 3.7.
Comportement par défaut
CSP implémente un certain nombre de politiques par défaut, qui peuvent être débrayées. Sont donc interdits :
- l'exécution de code placé directement dans la page, que ce soit au sein de
balises
script, dans les liens (<a href="javascript..." />) ou les gestionnaires d'évènements (onclick...)[1]; - l'exécution de code à partir d'une chaîne de caractère, donc par exemple
l'utilisation de la fonction
eval; - l'utilisation d'URI de type
data:...; - les binding XBL, hormis ceux provenant du chrome (je crois que Firefox est le seul navigateur à implémenter XBL, donc si vous ne comprenez pas ce que ça veut dire, ça n'est pas bien grave);
La politique de sécurité permet ensuite de définir, pour chaque type de contenu (script, images, etc), les URI à partir desquelles le navigateur est autorisé à télécharger le contenu.
Syntaxe
Une politique de sécurité se compose de directives, séparées par des point-virgules. Chaque directive comporte un nom et une liste de valeurs, séparées par des espaces. Les directives disponibles sont:
allowdéfinit la politique par défaut. Elle doit toujours être définie;optionspermet de définir... des options. Pour l'instant seules deux valeurs sont possibles :eval-scriptpour autoriser les fonction de typeeval, etinline-script, pour permettre la présence de code directement dans la page;font-srcpour la source des fontes chargées via la propriété CSSfont-src;frame-srcpour la source desframeset desiframes;img-srcpour la source des images et de la favicon;media-srcpour la source des élémentsaudioetvideo;object-srcpour la source des élémentsapplet,embedetobject;script-srcpour la source des scriptsstyle-srcpour la source des feuilles de style externes;xhr-srcpour les requêtesXMLHttpRequest;frame-ancestorsdéfinit les sources autorisées à afficher le contenu à l'intérieur d'une frame. Cela permet donc d'interdire qu'une page soit insérée dans une autre à l'aide d'une iframe (une technique couramment utilisée dans les attaques par clickjacking);policy-uri: URI d'un fichier contenant la description de la politique;report-uri: URI où envoyer un rapport en cas de tentative de violation d'une règle
La source peut être soit self, soit none soit une
URI. self signifie que ne sont autorisés que les contenus délivré
par le même scheme, le même hôte et le même port. Les URI peuvent contenir des
méta-caractères, par exemple *.mozilla.org.
Par défaut, les sites ne peuvent pas mélanger de contenu sécurisé et non sécurisé. Pour l'autoriser, il faudra le déclarer explicitement, par exemple:
X-Content-Security-Policy: allow http://*.clochix.net https://*.clochix.net
La description des politiques de sécurité et le comportement à adopter en
cas de violation peuvent être décrits dans des documents externes, via
policy-uri et report-uri, mais ceux-ci doivent avoir
la même origine que le document auquel elles s'appliquent;
Enfin, la spécification précise de plus le comportement à adopter en présence de plusieurs plusieurs politiques.
Les rapports
Si le navigateur détecte qu'une page essaie de violer une des règles
définies, il peut envoyer via une requête HTTP POST, un rapport à l'URI définie
via report-uri. Ce rapport est un document XML.
Les rapports contiennent la requête avec tous ses entêtes, l'URI du contenu bloqué, la directive à l'origine du blocage, et l'ensemble des directives appliquées. Un rapport pourra ressembler à
<csp-report>
<request>GET /index.html HTTP/1.1</request>
<request-headers><![CDATA[
Host: example.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
]]></request-headers>
<blocked-uri>http://evil.com/some_image.png</blocked-uri>
<violated-directive>img-src self</violated-directive>
<original-policy>allow none; img-src *, allow self; img-src self</original-policy>
</csp-report>
Ce qui signifie qu'une page a essayé de charger une image depuis un site externe, alors que seules les images du site d'origine sont autorisées.
Pour faciliter la mise au point des directives, on pourra remplacer
X-Content-Security-Policy par
X-Content-Security-Policy-Report-Only. Dans ce cas le navigateur
se contentera d'envoyer des rapport sans bloquer le contenu qui viole la
directive.
Exemples
Autoriser l'exécution de code placé directement dans la page:
X-Content-Security-Policy: allow 'self'; script-src inline;
ou
X-Content-Security-Policy: allow 'self'; options inline-script;
Autoriser l'utilisation des fonctions qui exécutent du code à partir d'une chaîne de caractère:
X-Content-Security-Policy: allow 'self'; script-src eval;
ou
X-Content-Security-Policy: allow 'self'; options eval-script;
Autoriser les images à utiliser le scheme data: :
X-Content-Security-Policy: allow self; img-src data;
Autoriser les images de toute origine, les plugins de certains sites, les sites uniquement depuis le domaine trustedscripts.example.com et le reste du contenu uniquement depuis le serveur d'origine:
X-Content-Security-Policy: allow 'self'; img-src *; \
object-src media1.com media2.com *.cdn.com; \
script-src trustedscripts.example.com
N'autoriser que le contenu sécurité par SSL:
X-Content-Security-Policy: allow https://*:443
Pour aller plus loin
Outre le Content Security Policy trois autres projets sont en cours pour renforcer la sécurité de Firefox :
Origin vise à prévenir
les attaques dites CSRF. Celles-ci consistent à obtenir du navigateur qu'il
effectue une requête déclenchant une action. Par exemple si l'utilisateur est
connecté à un webmail, on essaiera de lui faire afficher une image dont l'URL
correspond à une action du webmail. Le navigateur, pour récupérer l'image,
exécutera la requête et déclenchera l'action. Les CSRF ne fonctionnent que pour
les actions accessibles via des requêtes HTTP GET$$pour celles
nécessitant un HTTP POST, existent des attaques proches, le vol de
clic (clickjacking), qui consistent à amener l'utilisateur à cliquer
sur un bouton qui déclenchera le POST. Pour lutter contre les CSRF, Brandon
Sterne et les équipes de Mozilla proposent que dans certains cas, le navigateur
ajoute aux entêtes qu'il envoie au serveur l'origine de la requête (le site
d'où elle provient), charge au serveur de déterminer s'il accepte de la traiter
ou non. La proposition est en cours de soumission à l'IETF pour devenir un
standard et un prototype est attendu pour la fin 2009.
Force-TLS propose aux sites d'ajouter un entête HTTP indiquant qu'ils ne doivent à l'avenir être contactés que via une connexion HTTPS. Un prototype est disponible sous la forme d'une extension.
Le "gros" morceau est bien sûr Electrolysis qui vise à utiliser des processus séparés pour l'affichage du navigateur, des pages et des plugins, afin de circonscrire au maximum les potentiels problèmes (plantages ou attaques).
En conclusion
La mise en œuvre de politiques de sécurité via le Content Security Policy ne sera pas forcément simple, car pour être efficace il faudra appliquer des règles strictes, et bon nombre d'applications existantes devront être modifiées pour en tirer partie. Mais à terme, cela ne peut que s'avérer payant, car cela fournit un garde-fou précieux contre bon-nombre d'attaques.
Il ne reste plus qu'à espérer que la spécification soit reprises par les autres fabriquants de navigateurs et devienne une norme.
Ajout du 07.10 : billet de Chris Blizzard sur HMO
Notes
[1] en terme d'accessibilité, il est cependant recommandé
de préférer les onclick aux addEventListener pour
exécuter du code, afin qu'un lecteur d'écran par exemple sache que le clic sur
un élément déclenche une action. Mais ce n'est qu'un pis-aller. La vrai
solution passe par l'utilisation de WAI-ARIA pour indiquer le rôle de
l'élément
Commentaires
Merci pour tous ces détails.
Si je comprends bien, ça va aussi "forcer" à coder proprement le javascript.
Je bosse en ce moment avec Magento, et vu comment ils gèrent le JS, ça va être dur à rendre tout ça compatible...
En attendant, le plus simple est tout de même d'utiliser no-script qui protège de pas mal de trucs dont le clickjacking.
@Nath : oui tout à fait, ça va obliger à vraiment bien séparer le contenu et le code, plus de mélange de HTML et de JavaScript. D'une manière générale, la plupart des techniques pour rendre un code plus sûr en améliorent aussi la qualité.
@Arkh : je ne suis vraiment pas fan de NoScript. Et je pense que c'est un truc pour utilisateur averti, puisqu'il faut en permanence prendre des décisions sur ce qu'on autorise ou pas. CSP, si elle était adoptée par les fondeurs de navigateurs et de sites, serait transparente pour les utilisateurs, donc me semble meilleure.
Sinon, ma solution préférée est d'utiliser simultanément plusieurs profils de Firefox, avec des niveaux de sécurité différents : un réservé aux sites de confiances sur lesquels je me connecte, et un pour surfer dans la nature. Celui-ci refuse les cookies, les redirections, certaines actions des scripts etc.
Noscript permet de bénéficier de diverses protections même lorsqu'on le laisse en mode ouvert (tout autorisé) : ses filtres anti-XSS, clear jacking, quelques contre-mesures anti CSRF et dernièrement l'implémentation de Strict Transport Policy.
Il est certain que si tous les browsers et webdevs faisaient leur boulot niveau sécurité, ça serait top. En attendant noscript bénéficie de mises à jours bien plus rapides que les browsers et n'a qu'une chose en tête : la sécurité.
Et bloquer google analytics : priceless.
merci pour cette info. sécurité...
reste à attendre et espérer l'adoption rapide par les autres navigateurs...
dommage que l'extension Firefox, ne soit pas compatible avec la version stable (3.5.*) pour avoir cette fonctionnalité sur mon navigateur habituel...
"Enfin, la spécification précise de plus le comportement à adopter en présence de plusieurs plusieurs politiques."
à remplacer par "Enfin, la spécification précise de plus le comportement à adopter en présence de plusieurs politiques." (un "plusieurs" en moins)
@^fabrice^^ : merci j'ai corrigé la typo.
Il me semble que l'extension n'implémente pas la dernière version de la spécification, donc la seule façon de tester pour l'instant est de télécharger une version spécifique avec le support de CSP ou d'attendre que ça atterrisse dans les nightlies.