Le renforcement de la sécurité des applications et sites web avec CSP

Spécialité(s)


Résumé

CSP définit une politique de sécurité de contenu de l'application web, qui fixe les listes des sources de confiance pour ses ressources (scripts, styles, images, etc.). Le navigateur bloque les téléchargements vers les sources non autorisées, ce qui élimine des attaques côté client, telles que le XSS.


Body

Au cours des cinq dernières années, neuf milliards de données ont été volées dans le monde. La tendance est à la hausse, près de deux milliards de données ont été dérobées lors du premier semestre 2017, ce qui est supérieur à la totalité des données volées en 2016. Chaque seconde environ 122 enregistrements sont volés [1]. La cause principale du vol de données est le vol d'identité, la France en est la deuxième victime mondiale, après les États-Unis [2]. Le vol d'identité peut notamment être réalisé par des attaques d'hameçonnage ou de vol de session. Les applications et sites web vulnérables aux injections de contenu et aux XSS (Cross Site Scripting) sont donc une des causes de vol de données, car elles permettent ces attaques.

Les applications et sites web sont la cible d'attaques diverses côté client : défiguration, détournement de clics, hameçonnage, vol de session. Les conséquences du piratage peuvent être lourdes pour les entreprises et administrations qui en sont victimes : atteinte à la réputation, poursuites et condamnations judiciaires, pertes financières. Les clients de ces applications peuvent être victimes d'exploitation de leurs données bancaires, d'usurpation d'identité, ou encore de révélation d'informations personnelles qui peuvent avoir des conséquences tragiques lorsqu'elles nuisent à la réputation (démissions, chantages ou suicides lors de la divulgation de données de sites de rencontres adultères).

Pour se protéger des attaques, les applications web doivent filtrer toutes les données provenant de l'utilisateur avant de les utiliser et protéger toutes les sorties. Parfois, le filtrage est partiel, inexistant ou trop permissif. De même la protection de certaines sorties peut être inexistante ou insuffisante. Les données fournies par des sociétés et organisations spécialisées en sécurité indiquent qu'une majorité d'applications contient des vulnérabilités dues à des problèmes de filtrage et de protection. Selon Symantec, trois quarts des sites web légitimes ont des vulnérabilités exploitables [2]. Dans son Top Ten 2017 des risques de sécurité les plus critiques, l'OWASP indique que le XSS est la deuxième faille la plus répandue dans les applications web, elle est présente dans environ deux tiers de ces applications [3]. Le XSS fait partie des trois vecteurs d'attaques les plus courants au quatrième trimestre 2017 [4].

Cet article explique comment renforcer la sécurité des applications et sites web contre des attaques XSS et d'injection de contenu, en définissant une politique de sécurité de contenu ou CSP. Cette politique, proposée par le W3C [5], définit des listes blanches de sources de confiance globalement ou pour chaque type de ressources utilisées par l'application. Il est par exemple possible d'indiquer que les scripts ne peuvent être téléchargés que depuis le serveur web qui héberge l'application, dans ce cas, le navigateur bloque le téléchargement et l'exécution de scripts JavaScript externes dont l'URL a été injectée par un attaquant. CSP ne supprime pas les vulnérabilités, mais limite les possibilités d'exploitation, c'est une technique de défense en profondeur, qui est complémentaire au filtrage des entrées et à la protection des sorties. CSP repose sur l'utilisation d'un champ d'en-tête de la réponse HTTP, Content-Security-Policy, qui peut être défini par le développeur ou par l'administrateur système.

Après avoir présenté des attaques côté client, nous expliquerons comment ajouter un champ d'en-tête dans la réponse HTTP. Nous décrirons les directives qui peuvent être utilisées pour définir la politique de sécurité de contenu, afin de protéger des attaques et d'envoyer un rapport d'incident au serveur. Nous expliquerons comment mettre en place CSP, quels sont ses avantages et inconvénients et son support par les navigateurs.

1. Attaques côté client

Les applications web sont la cible de nombreuses attaques, dont certaines sont exécutées côté client : hameçonnage, défiguration, vol de session, détournement de clic. Un filtrage inexistant ou insuffisant et une protection des sorties vers le navigateur inexistante ou insuffisante rendent l'application vulnérable aux XSS et à l'usurpation de données. Ces vulnérabilités permettent à un attaquant d'injecter des éléments HTML, des styles CSS, du code JavaScript, qui sont interprétés par le navigateur. Ces attaques exploitent la confiance qu'un utilisateur ou que le navigateur a en un site web, la victime des attaques côté client est l'utilisateur de l'application.

1.1 Cross-Site Scripting (XSS)

Le XSS consiste à faire exécuter un code malveillant par le navigateur. Il rend possible des attaques côté client, telles que la défiguration, l'hameçonnage via une redirection vers la contrefaçon du site, le détournement de clics et le vol de session. Les figures 1 et 2 illustrent une attaque XSS stockée dont le but est de voler le jeton de session de l'administrateur de l'application, afin d'accéder à l'application sans s'être préalablement authentifié.

Le pirate injecte un script malveillant via un formulaire d'inscription (figure 1-1). Le formulaire est ensuite envoyé par le navigateur (figure 1-2) à l'application (figure 1-3). Si l'application ne filtre pas correctement les données provenant du formulaire, le contenu malicieux est enregistré dans la base de données (figure 1-4).

csp_figure_01

Fig. 1 : Envoi d'un XSS par le pirate.

Une fois l'administrateur de l'application authentifié, il reçoit un jeton de session dans un cookie, ce jeton permet à l'application de le reconnaître pendant toute la durée de sa navigation. L'administrateur interroge l'application afin d'obtenir la liste des personnes inscrites dans la base de données. Le XSS stocké (figure 2-1) est récupéré par l'application web (figure 2-2), celle-ci génère dynamiquement un document HTML contenant la liste des inscrits (figure 2-3). L'application ne protégeant pas correctement les sorties, le XSS est inclus dans le document HTML. Le navigateur analyse le code HTML, il affiche la liste des personnes (figure 2-4). Pour exécuter le code JavaScript injecté dans le document, il doit télécharger le fichier c.js (figure 2-5), situé sur le serveur fictif bad.org. Ce dernier lui envoie un fichier JavaScript (figure 2-6) qui contient une instruction indiquant au navigateur qu'il doit ajouter un élément dans le document. Le navigateur évalue l'expression dans document.write (figure 2-7), qui demande la création d'un élément img dont la source est le fichier c sur le serveur bad.org, avec une partie chaîne de requête contenant les cookies associés à la page HTML. Le navigateur envoie au serveur bad.org (figure 2-8) une requête contenant le jeton de session de l'administrateur.

Si les sessions ne sont pas correctement gérées, le pirate pourra ensuite injecter ce cookie dans son navigateur afin de se connecter à l'application en tant qu'administrateur.

csp_figure_02

Fig. 2 : Exécution du XSS dans l'interface de l'administrateur.

1.2 Usurpation de contenu

L'usurpation de contenu ou de données est une attaque qui consiste à faire croire à un utilisateur qu'un contenu injecté (HTML, style CSS, texte), est un contenu légitime de l'application. Il est ainsi possible d'effectuer des défigurations, des détournements de clics et de l'hameçonnage.

La figure 3 montre un exemple d'hameçonnage, réalisé au moyen d'une injection d'un cadre flottant. De la même manière que pour l'attaque XSS, le pirate envoie un élément iframe via le formulaire d'inscription de l'application, l'iframe est stocké dans la base de données (figure 3-1). Le cadre flottant permet d'afficher une page web à l'intérieur d'une autre page web. Le contenu du cadre est une contrefaçon de la page d'authentification de l'application, cette page contenant le formulaire d'authentification est située sur le serveur du pirate (figure 3-2). L'administrateur demande au serveur la liste des inscrits, l'application (figure 3-3) extrait la liste de la base de données, puis génère et envoie au navigateur un document HTML (figure 3-4) qui comporte la liste avec le cadre flottant injecté. Le navigateur demande au serveur bad.org la page HTML afin de pouvoir afficher le contenu du cadre flottant (figure 3-5). Le serveur externe lui envoie le fichier page.html, qui contient la fausse page d'authentification (figure 3-6). Le navigateur applique le style CSS qui a été injecté par le pirate en même temps que le cadre flottant dans l'attribut style de l'élément iframe (figure 3-7). Grâce à ce style, le contenu illégitime recouvre et masque intégralement le contenu légitime de l'application. Lorsque l'administrateur authentifié consulte la liste des inscrits, la fausse page d'authentification recouvre donc la liste (figure 3-8). L'administrateur, pensant avoir été déconnecté, remplit le faux formulaire d'authentification puis l'envoie. Les données du formulaire sont transmises au site qui héberge la contrefaçon du formulaire (figure 3-9), ce qui permet au pirate de recevoir les identifiants de l'administrateur.

csp_figure_03

Fig. 3 : Exécution d'un hameçonnage par usurpation de données.

Ces attaques, qui impliquent de télécharger des ressources du site pirate, peuvent facilement être neutralisées grâce à CSP.

2. Ajouter un champ d'en-tête HTTP

Les clients (navigateurs) et les serveurs web communiquent par le biais du protocole de transport HTTP (HyperText Transfer Protocol). Lorsqu'un navigateur veut obtenir une ressource, telle qu'une page HTML, une image, un script JavaScript ou un fichier CSS, il envoie une requête HTTP au serveur (figure 4-1). Celui-ci la traite et envoie une réponse (figure 4-2). Les navigateurs proposent des outils d'inspection, leur onglet Réseau permet de visualiser le détail des échanges HTTP pour chaque ressource.

2.1 Réponse HTTP

La réponse HTTP est composée de deux parties séparées par une ligne vide : l’en-tête (figure 4-3) et le corps qui contient la ressource demandée (figure 4-4).

L'en-tête de la réponse fournit des méta-informations sur la ressource envoyée et sur le serveur lui-même. Il comporte sur la première ligne la version du protocole et le code d'état de la réponse, 200 en cas de succès. Les lignes suivantes donnent des informations sur le serveur web et sur la ressource : type de média, taille, encodage.

Les informations sont transmises sous la forme de paires nom-valeur, séparées par un caractère deux-points : Nom-Du-Champ: valeur. Dans la figure 4, la ressource est un document HTML (champ Content-Type) de 5400 octets (champ Content-Length). La liste des champs d'en-tête HTTP est disponible dans un registre maintenu par le IANA [6], avec pour chaque champ une référence au document RFC de l'IETF qui le décrit [7]. Des champs d'en-tête non standards, c'est-à-dire ne faisant pas partie de la liste de l'IANA, peuvent également être envoyés dans la réponse.

csp_figure_04

Fig. 4 : Messages HTTP avec modification de l'en-tête de la réponse.

Il est possible d'ajouter des champs dans l'en-tête de la réponse HTTP, soit directement dans le code de l'application (figure 4-a), soit dans un fichier de configuration du serveur web (figure 4-b).

2.2 Ajout dans le code

Les langages de programmation pour le web, les bibliothèques et framework de développement proposent des fonctions, méthodes ou propriétés pour définir des champs d'en-tête HTTP. Par exemple, PHP fournit la fonction header. Elle reçoit en paramètre une chaîne de caractères comportant le nom du champ et sa valeur, séparés par le caractère deux-points. L'instruction ci-après ajoute un champ d'en-tête Author dont la valeur est MAMC :

header('Author:MAMC');

Le champ d'en-tête ainsi défini concerne la ressource générée dynamiquement. Pour que le champ soit envoyé au navigateur par tous les scripts de l'application, il faudra utiliser la fonction header dans un fichier inclus dans tous les scripts.

2.3 Ajout dans le fichier de configuration

L'ajout du champ d'en-tête peut également être effectué par l'administrateur système dans le fichier de configuration du serveur web. La figure 4-b montre les directives Apache et Nginx qui contrôlent les champs d'en-tête de la réponse. Par exemple, les directives Apache ci-après chargent le module headers_module  [8] et ajoutent un en-tête HTTP Author dont la valeur est MC :

LoadModule headers_module modules/mod_headers.so

<IfModule headers_module>

    Header set Author "MC"

</IfModule>

Le champ d'en-tête peut être défini globalement dans le fichier de configuration, dans ce cas il est envoyé dans toutes les réponses HTTP retournées par le serveur - quel que soit le type de la ressource - ou localement pour un répertoire, ce qui permet de restreindre l'envoi du champ à une application web.

2.4 Ajout dans un .htaccess

La directive Header peut également être placée dans un fichier .htaccess dans le répertoire de l'application web, si l'administrateur système autorise l'activation des directives dans ces fichiers [9]. Ceci permet au développeur de définir les champs d'en-tête et facilite leur maintenance, car la modification du fichier ne nécessite pas de droit particulier d'administration. L'extrait du fichier .htaccess ci-après définit le champ d'en-tête Author avec la valeur MA.

Header set Author "MA"

2.5 Priorité en cas de collision de champ

Les champs d'en-tête pouvant être ajoutés dans le code, dans un fichier .htaccess ou dans le fichier de configuration du serveur, il peut arriver qu'un même champ soit défini à différents niveaux.

D'une manière générale, les en-têtes définis dans la configuration ont priorité sur ceux ajoutés dans le code. Le .htaccess quant à lui est prioritaire sur la configuration générale du serveur.

En fonction de l'argument utilisé dans Header pour réaliser l'ajout, la valeur peut être écrasée (set), ajoutée (append) ou fusionnée (merge). Le tableau illustre l'ordre des priorités lorsque le champ Author est ajouté à différents niveaux. La première ligne montre que lorsque l'ajout est réalisé avec set dans le .htaccess, le navigateur reçoit MA comme auteur, alors qu'un ajout avec append envoie les deux valeurs MAMC et MA, séparées par une virgule. Si le .htaccess et le code ajoutent des valeurs identiques pour un même champ avec append, les deux valeurs sont envoyées au navigateur, alors que merge évite l'envoi de doublons.

Valeur dans le code

Valeur dans le .htaccess

Valeur dans la config Apache

Résultat avec set

Résultat avec append

MAMC

MA

 

MA

MAMC, MA

MAMC

 

MC

MC

MAMC, MC

 

MA

MC

MA

MC, MA

MAMC

MA

MC

MA

MAMC, MC, MA

3. Définir une politique de sécurité avec CSP

La politique de sécurité du contenu de l'application web définit des listes blanches de sources de confiance pour le téléchargement des ressources de l'application. Elle est transmise grâce à un champ d'en-tête HTTP, comportant des directives. CSP est une recommandation du W3C [5], établie par un groupe de travail d'experts de la sécurité et du Web. Le W3C a travaillé sur plusieurs versions de CSP, la version 1 est obsolète, la majorité de ses directives est présente dans la version 2, qui est la version courante. Une version 3 est en cours, mais le document est encore à l'état de brouillon de travail.

3.1 Champ Content-Security-Policy

La politique de sécurité du contenu de l'application web est définie grâce au champ d'en-tête Content-Security-Policy de la réponse HTTP.

Les directives de sécurité sont transmises au navigateur dans la partie valeur du champ d'en-tête Content-Security-Policy. La politique est constituée d'une ou plusieurs directives séparées par un caractère point-virgule :

Content-Security-Policy: <directive>[; <directive>]+

3.2 Directives

Une directive est composée d'un nom et d'une valeur, séparés par un caractère espace. Le nom indique le type de ressource, par exemple img-src, script-src et style-src définissent respectivement la politique pour les images, scripts JavaScript et feuilles de style CSS. La valeur définit la sécurité des téléchargements pour le type de ressource.

La politique générale de téléchargement est définie avec la directive default-src. Elle est utilisée par les autres directives, si elles n'ont pas été définies dans la CSP. Dans l'exemple, par défaut le navigateur n'est autorisé à télécharger que les ressources provenant de la même origine que la page HTML :

Content-Security-Policy: default-src 'self'

Le tableau présente quelques directives CSP, en indiquant leur support par les différentes versions, ainsi que les ressources, éléments et attributs concernés.

Quelques directives

Version CSP

Type de ressource

Élément ou attribut concerné

script-src

≥ 1

scripts JavaScript

<script>

img-src

≥ 1

images

<img>

style-src

≥ 1

feuilles de style

<style>

font-src

≥ 1

polices

@font-face

media-src

≥ 1

vidéos et sons

<video>, <audio>

object-src

≥ 1

objets

<object>

frame-src

child-src

1 (obsolète)

2

cadres

<frame>, <iframe>

connect-src

≥ 1

requêtes AJAX

 

form-action

≥ 1.1

envois de formulaires

<form action="...">

base-uri

2

URL relatives du document

<base>

default-src

≥ 1

politique générale de téléchargement

 

3.3 Valeurs des directives

La valeur d'une directive est composée d'une liste de sources séparées par des espaces. Une source est un mot-clé, une URL ou un nom de domaine. Les mots-clés sont entourés d'apostrophes pour les différencier des noms de domaines.

Le mot-clé self autorise les téléchargements de même origine que l'URL de la page HTML à laquelle la politique est appliquée. Le mot-clé none interdit le téléchargement de ressources. La politique ci-après bloque le téléchargement de tous les cadres flottants et autorise le téléchargement de scripts uniquement s'ils proviennent de la même origine que l'URL courante du document HTML. Cette politique bloque les deux attaques présentées dans la section 1 de l'article :

child-src 'none'; script-src 'self'

Le caractère générique * peut être utilisé dans la source pour représenter une séquence quelconque de caractères.

La directive suivante indique au navigateur que les images ne peuvent être téléchargées que depuis le serveur web qui héberge l'application (mot-clé self) ou depuis le domaine openclipart.org ou encore depuis tout sous-domaine de mesimages.fr :

img-src 'self' openclipart.org *.mesimages.fr

4. Politique de sécurité JavaScript

Le code JavaScript peut être intégré dans un document HTML :

  • dans un fichier externe importé dans la page, l'adresse de ce fichier est définie dans l'attribut src de l'élément script (figure 5-2) ;
  • à l'intérieur de l'élément script, les instructions sont placées entre les balises ouvrante et fermante (figure 5-7) ;
  • dans un attribut événementiel d'un élément HTML : onclick, onchange, etc. ;
  • dans un attribut acceptant une URL (href, src) en utilisant javascript: devant le code.

4.1 Scripts externes

Placer le code JavaScript dans un fichier externe sépare intégralement le comportement JavaScript du contenu du document. Le navigateur télécharge le fichier JavaScript dont l'URL est indiquée dans l'attribut src de l'élément script, puis l'exécute. C'est cette méthode qui doit être privilégiée pour des raisons de sécurité.

CSP permet de définir une liste blanche de sources de confiance pour les scripts, avec la directive script-src. La figure 5 illustre le comportement du navigateur lorsqu'il reçoit une politique pour les scripts. Dans l'exemple, la politique envoyée (figure 5-1) indique que les scripts peuvent être téléchargés s'ils proviennent de la même origine ou du domaine code.jquery.com. Le navigateur télécharge donc le script fonction.js (figure 5-2), qui est situé sur le serveur qui a envoyé le document HTML, ainsi que le script jQuery (figure 5-3).

Dans l'exemple de la section 1, un XSS avait été injecté par un pirate, demandant au navigateur le téléchargement d'un script sur le serveur bad.org. La politique CSP protège de ce type d'attaque. En effet, la source bad.org ne faisant pas partie de la liste blanche, le navigateur ne télécharge pas le script c.js (figure 5-4). Le navigateur journalise l'interdiction de téléchargement dans la console de l'inspecteur du navigateur (figure 5-5).

4.2 Code embarqué dans la page web

Lorsqu'un champ Content-Security-Policy est envoyé, le comportement par défaut des navigateurs est de ne pas exécuter le code JavaScript embarqué dans le HTML, sauf si la politique l'autorise explicitement. En effet, un navigateur ne peut pas déterminer si un élément script contenant des instructions JavaScript est légitime ou s'il a été injecté dans la page HTML par un pirate. La désactivation par défaut permet de supprimer les XSS. Toutes les instructions JavaScript embarquées directement dans la page HTML sont bloquées, que ce soit dans les éléments script, dans les attributs événementiels (onclick, onchange, …) ou ceux qui acceptent des URL (href, src).

Il est parfois impossible ou très difficile de placer en externe le code JavaScript d'une application déjà en production. CSP 2 a introduit un mécanisme pour indiquer au navigateur qu'un script embarqué est légitime en lui attribuant un nonce, c'est-à-dire un nombre à usage unique encodé en base 64 et suffisamment difficile à prédire. Le développeur doit générer une valeur aléatoire à usage unique et la transmettre dans le mot-clé nonce dans script-src (figure 5-1). La même valeur doit figurer dans l'attribut nonce de l'élément script (figure 5-6). Le navigateur vérifie que le nonce du script embarqué correspond à celui de la CSP. Si ce n'est pas le cas, il bloque l'exécution, sinon le JavaScript est exécuté. Ceci permet d'exécuter le script de la figure 5-6, tout en bloquant le XSS (figure 5-7).

CSP 2 permet également d'utiliser un hash du script à la place du nonce. Dans ce cas, il faut calculer le hash du script, puis ajouter dans la politique un mot-clé qui indique l'algorithme (SHA-256, SHA-384 ou SHA-512), suivi du hash, par exemple 'sha256-Yb2aHKnv…'.

Si vous ne pouvez pas séparer le code ou utiliser un nonce ou un hash, ou que vous avez du code dans des attributs, vous pouvez dégrader la protection CSP pour les scripts, afin de pouvoir bénéficier de la protection CSP pour d'autres ressources, sans bloquer le fonctionnement de l'application. Le mot-clé unsafe-inline dans script-src autorise l'exécution du code embarqué. Dans ce cas, vous ne serez protégés que contre les XSS demandant le téléchargement de fichiers vers des sources non autorisées, tous les autres XSS seront exécutés. Le mot-clé unsafe-eval permet l'évaluation de code JavaScript dans la fonction eval, il doit être évité, sauf si une bibliothèque indispensable à votre application utilise cette fonction.

La meilleure sécurité est de ne pas embarquer de code JavaScript dans le document HTML, dans le cas contraire l'utilisation d'un nonce ou d'un hash offrent une meilleure sécurité que unsafe-inline, qui ne doit être utilisé qu'en dernier recours.

csp_figure_05

Fig. 5 : Comportement du navigateur avec une politique JavaScript.

5. Obtenir un rapport de violation

En cas de violation de la politique, le navigateur peut envoyer un rapport au serveur, ce qui permet d'alerter le développeur et/ou l'administrateur. Il est ainsi possible de détecter des attaques côté client et de prévenir le développeur afin qu'il en détermine la cause et qu'il corrige la vulnérabilité.

La directive CSP report-uri indique au navigateur d'envoyer un rapport de violation, lorsqu'il bloque un téléchargement. Dans la version 3 de CSP, cette directive sera remplacée par report-to. La politique ci-après interdit le téléchargement de scripts JavaScript provenant d'autres origines que le fichier HTML. Le navigateur doit envoyer les rapports de violation au script logCSP.php situé sur le serveur web hébergeant le fichier HTML :

Content-Security-Policy: script-src 'self'; report-uri logCSP.php

Le rapport de violation est envoyé au serveur par la méthode POST, au format JSON. Dans l'exemple, le rapport indique que la page test.html (document-uri) a demandé le téléchargement d'un script JavaScript hébergé par code.jquery.com (blocked-uri), ce qui viole la directive script-src (violated-directive) de la politique reçue (original-policy).

{ "csp-report":

 {

"document-uri": "http://localhost/test.html",

"referrer": "http://localhost/accueil.html",

"violated-directive": "script-src 'self' ",

"original-policy": "script-src 'self'; report-uri logCSP.php"

"blocked-uri": "http://code.jquery.com"

 }

}

Lorsque le serveur reçoit le rapport de violation, le script qui le traite peut, par exemple, enregistrer dans un fichier de log le rapport et/ou envoyer un mail au développeur. Le script suivant, montre comment récupérer en PHP le rapport brut et l'ajouter dans le journal security.log avec la date courante. Afin de réduire le code, nous avons omis les vérifications d'ouverture et fermeture de fichier, du format des données reçues, nous n'avons pas décodé le JSON, ni formaté les données pour embellir le texte stocké dans les logs.

<?php

// récupérer les données brutes du POST

$cspdata = file_get_contents("php://input");

// ouvrir en ajout le fichier de log

$fp = fopen('log/security.log', 'a+');

// récupérer la date et l'heure courante

$time = date('d/m/Y H:i:s');

// écrire la date et le rapport dans le fichier

fwrite($fp, $time . "\n". $cspdata . "\n");

// fermer le fichier

fclose($fp);

6. Implémentation

CSP étant une recommandation du W3C, il est bien implémenté dans les navigateurs. D'après le site Can I Use [10], 94% des navigateurs utilisés dans le monde supportent totalement (91%) ou partiellement (3%) la version 1 de CSP. La version 2 a un support global de 81% (figure 6).

csp_figure_06

Fig. 6 : Support de CSP 2 par les navigateurs.

Mettre en place CSP demande des modifications dans le code des applications et sites web déjà en production, afin de séparer le style CSS et le comportement JavaScript du code HTML. Ceci a retardé son adoption ces dernières années par les sites, services et applications web les plus populaires. À présent, plusieurs CMS et framework de développement proposent des plugins ou supportent en natif CSP, parfois en définissant des nonce et hash. De plus en plus d'applications et sites web utilisent CSP. Ce champ est notamment présent dans les en-têtes HTTP des réseaux sociaux Twitter, Facebook et Tumblr, dans le réseau social professionnel LinkedIn et dans le réseau social visuel Pinterest.

Déployer CSP force aux bonnes pratiques de programmation web. Par défaut, le style CSS ne doit pas être placé dans l'attribut style ou dans l'élément style, il est défini en externe. Le code JavaScript doit être placé dans des fichiers externes et l'évaluation de code avec la fonction eval est interdite. Le code JavaScript est donc discret, ou non intrusif, c'est-à-dire qu'il ne comporte plus d'attributs événementiels, tels que onclick, ni de code dans les attributs d'URL via javascript: ou d'instructions dans les éléments script.

Lorsqu'une application comporte des briques logicielles qui génèrent du code JavaScript embarqué dans le HTML ou que sa réécriture demanderait plusieurs semaines ou mois de développement, il est possible de mettre en place une politique stricte pour certaines ressources (images, polices, cadres flottants, requêtes AJAX, etc.), tout en relâchant la politique de sécurité d'autres ressources. Il est ainsi possible d'autoriser l'insertion de styles et de scripts dans la page HTML en utilisant des nonces, ou de supprimer l'interdiction de l'exécution de JavaScript et CSS intégrés. Lors du développement d'une nouvelle application web, il faut privilégier la séparation du style, du comportement et du contenu, car cette architecture offre la meilleure protection CSP.

Pour mettre en place CSP, il faut :

  • établir la liste des sources de confiance pour chaque type de ressource ;
  • placer tout le code JavaScript dans des fichiers externes, si ce n'est pas possible utiliser des nonce ou des hashes ;
  • placer tout le style CSS dans des fichiers externes, car CSP bloque par défaut l'exécution du style embarqué directement dans la page web ;
  • définir la liste des sources de confiance par défaut à none, pour tout interdire puis définir la politique pour chaque type de ressource nécessaire à l'application ;
  • prévoir un script pour récupérer les rapports de violation.

Il faudra ensuite veiller à maintenir la liste des sources lorsque de nouvelles origines seront introduites dans l'application.

Lorsque vous déployez la politique, vous pouvez utiliser l'onglet Console de l'inspecteur des navigateurs afin de visualiser les téléchargements bloqués. Cette méthode est cependant fastidieuse, il est préférable de générer et stocker des rapports de violation avec report-uri et de travailler en mode sans blocage pendant toute la période de test de la politique. Vous pourrez ainsi obtenir dans le fichier de log la liste des ressources bloquées par la politique, tout en évitant des dysfonctionnements de l'application. Le rapport vous permettra de régler la politique afin que les ressources dont le téléchargement est légitime ne soient pas bloquées. Le mode sans blocage est obtenu en utilisant le champ d'en-tête Content-Security-Policy-Report-Only :

Content-Security-Policy-Report-Only: politique; report-uri URL

Les outils en ligne qui fournissent des analyses de sécurité des en-têtes HTTP ont intégré CSP dans leur évaluation [11, 12, 13]. Vous pouvez les utiliser, ainsi que les outils CSP Evaluator [14] et Report URI [15], qui évaluent la sécurité d'un CSP, afin de vérifier vos politiques et les améliorer.

Il est important de toujours garder à l'esprit qu'une politique trop permissive ou mal définie ne renforce pas la sécurité et que les navigateurs ignorent les directives qu'ils ne supportent pas. CSP, bien que très utile et efficace ne doit pas remplacer le filtrage des entrées et la protection des sorties.

Conclusion

CSP permet de bloquer l'exécution d'attaques côté client dans le navigateur et d'envoyer au serveur des rapports de violation. Il n'est pas destiné à remplacer le filtrage des entrées et la protection des sorties dans le code, mais à apporter une couche de sécurité supplémentaire pour empêcher l'exécution de XSS et l'interprétation de données injectées.

CSP est défini par le W3C, il est bien supporté par les navigateurs, les CMS et framework de développement ont évolué pour que les codes soient compatibles avec lui, de plus en plus d'applications et sites web l'utilisent et ce champ d'en-tête est pris en compte par les outils qui analysent la sécurité des applications et sites web. CSP est donc pérenne et mûr pour une utilisation en production. Nous vous invitons à renforcer la sécurité de vos applications et sites web avec CSP et à compléter cette protection par l'utilisation des autres champs d'en-tête de sécurité recommandés par l'OWASP [16]. Vous pourrez ensuite vérifier les en-têtes de sécurité de vos applications et améliorer vos politiques de sécurité grâce aux outils en ligne, tels que CSP Evaluator ou Check Your Headers.

Références

[1] Rapports de Gemalto, «Breach Level Index » de 2016 et 2017 : http://breachlevelindex.com/

[2] Rapport Symantec d'avril 2017,« Internet Security Threat Report 2017 »
https://www.symantec.com/security-center/threat-report

[3] Rapport de l'OWASP sur les 10 risques de sécurité les plus critiques « OWASP Top Ten 2017 »
https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project

[4] Rapport de la société Akamai sur l'état de la sécurité Internet au 4ème trimestre 2017, « State of the Internet Security – Q4 2017 report » : https://www.akamai.com/fr/fr/about/our-thinking/state-of-the-internet-report/

[5] Recommandation du W3C décrivant CSP, « Content Security Policy Level 2 » : https://www.w3.org/TR/CSP2/

[6] Registre du IANA des noms des champs d'en-tête HTTP : http://www.iana.org/assignments/message-headers/message-headers.xhtml

[7] Description des différentes versions du protocole HTTP dans les documents RFC de l'IETF (RFC 7230 pour HTTP/1.1) : https://www.rfc-editor.org/standards

[8] Description du module mod_headers d'Apache, qui permet de gérer les en-têtes HTTP : 
https://httpd.apache.org/docs/2.4/fr/mod/mod_headers.html

[9] Tutoriel du serveur HTTP Apache sur les fichiers .htaccess : https://httpd.apache.org/docs/2.4/fr/howto/htaccess.html

[10] Support de CSP par les navigateurs : https://caniuse.com/#search=csp

[11] Outil de scan d'en-tête securityheaders.io : https://securityheaders.io/

[12] Outil de scan d'en-tête Check Your Headers : https://cyh.herokuapp.com/cyh

[13] Outil de scan d'en-tête Observatory de Mozilla : https://observatory.mozilla.org/

[14] Outil d'évaluation de la sécurité d'un CSP, CSP Evaluator : https://csp-evaluator.withgoogle.com/

[15] Outil d'évaluation de la sécurité d'un CSP, Report URI : https://report-uri.com/home/analyse

[16] Description des en-têtes HTTP de sécurité sur le site de l'OWASP : 
https://www.owasp.org/index.php/OWASP_Secure_Headers_Project



Article rédigé par

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous