Guide complet pour améliorer la sécurité frontend avec CSP et CORS, protégeant vos applications web des menaces modernes.
Durcissement de la sécurité Frontend : Content Security Policy et CORS
Dans le paysage numérique interconnecté d'aujourd'hui, la sécurité frontend est primordiale. Les applications web sont de plus en plus ciblées par des attaques sophistiquées, rendant les mesures de sécurité robustes essentielles. Deux composants critiques d'une architecture frontend sécurisée sont la Content Security Policy (CSP) et le Cross-Origin Resource Sharing (CORS). Ce guide complet offre un aperçu approfondi de ces technologies, proposant des exemples pratiques et des insights actionnables pour vous aider à fortifier vos applications web contre les menaces modernes.
Qu'est-ce que la Content Security Policy (CSP) ?
La Content Security Policy (CSP) est une couche de sĂ©curitĂ© supplĂ©mentaire qui aide Ă dĂ©tecter et Ă attĂ©nuer certains types d'attaques, y compris les attaques par Cross-Site Scripting (XSS) et par injection de donnĂ©es. La CSP est implĂ©mentĂ©e par le serveur web qui envoie un en-tĂȘte de rĂ©ponse HTTP Content-Security-Policy au navigateur. Cet en-tĂȘte dĂ©finit une liste blanche des sources Ă partir desquelles le navigateur est autorisĂ© Ă charger des ressources. En restreignant les sources de contenu qu'un navigateur peut charger, la CSP rend beaucoup plus difficile pour les attaquants d'injecter du code malveillant sur votre site web.
Comment fonctionne la CSP
La CSP fonctionne en indiquant au navigateur de ne charger que les ressources (par exemple, scripts, feuilles de style, images, polices) provenant de sources approuvĂ©es. Ces sources sont spĂ©cifiĂ©es dans l'en-tĂȘte CSP Ă l'aide de directives. Si un navigateur tente de charger une ressource depuis une source qui n'est pas explicitement autorisĂ©e, il bloquera la requĂȘte et signalera une violation.
Directives CSP : Un aperçu complet
Les directives CSP contrĂŽlent les types de ressources qui peuvent ĂȘtre chargĂ©es Ă partir de sources spĂ©cifiques. Voici une ventilation de certaines des directives les plus importantes :
- default-src : Spécifie la source par défaut pour tous les types de contenu. Il s'agit d'une directive de repli qui s'applique lorsque d'autres directives, plus spécifiques, ne sont pas présentes.
- script-src : SpĂ©cifie les sources Ă partir desquelles les scripts peuvent ĂȘtre chargĂ©s. Ceci est crucial pour prĂ©venir les attaques XSS.
- style-src : SpĂ©cifie les sources Ă partir desquelles les feuilles de style peuvent ĂȘtre chargĂ©es.
- img-src : SpĂ©cifie les sources Ă partir desquelles les images peuvent ĂȘtre chargĂ©es.
- font-src : SpĂ©cifie les sources Ă partir desquelles les polices peuvent ĂȘtre chargĂ©es.
- media-src : SpĂ©cifie les sources Ă partir desquelles l'audio et la vidĂ©o peuvent ĂȘtre chargĂ©s.
- object-src : SpĂ©cifie les sources Ă partir desquelles les plugins (par exemple, Flash) peuvent ĂȘtre chargĂ©s. Ceci est souvent dĂ©fini sur 'none' pour dĂ©sactiver complĂštement les plugins en raison de leurs risques de sĂ©curitĂ© inhĂ©rents.
- frame-src : SpĂ©cifie les sources Ă partir desquelles les cadres (par exemple, <iframe>) peuvent ĂȘtre chargĂ©s.
- connect-src : Spécifie les URL auxquelles l'agent utilisateur peut se connecter à l'aide d'interfaces de script telles que XMLHttpRequest, WebSocket et EventSource.
- base-uri : SpĂ©cifie les URL qui peuvent ĂȘtre utilisĂ©es dans l'Ă©lĂ©ment <base> d'un document.
- form-action : SpĂ©cifie les URL vers lesquelles les soumissions de formulaires peuvent ĂȘtre envoyĂ©es.
- upgrade-insecure-requests : Indique Ă l'agent utilisateur de mettre Ă niveau automatiquement les requĂȘtes non sĂ©curisĂ©es (HTTP) vers des requĂȘtes sĂ©curisĂ©es (HTTPS).
- report-uri : SpĂ©cifie une URL oĂč le navigateur doit envoyer des rapports sur les violations de CSP. Cette directive est dĂ©prĂ©ciĂ©e au profit de `report-to`.
- report-to : SpĂ©cifie un nom de groupe de rapports dĂ©fini dans l'en-tĂȘte `Report-To`, oĂč le navigateur doit envoyer des rapports sur les violations de CSP.
Mots-clés de liste de sources CSP
Dans les directives CSP, vous pouvez utiliser des mots-clés de liste de sources pour définir les sources autorisées. Voici quelques mots-clés courants :
- 'self' : Autorise les ressources de la mĂȘme origine (schĂ©ma et hĂŽte) que le document.
- 'none' : Refuse les ressources de toutes les sources.
- 'unsafe-inline' : Autorise l'utilisation de scripts et de styles en ligne (par exemple, les balises <script> et les attributs de style). Ă utiliser avec une extrĂȘme prudence car cela affaiblit considĂ©rablement la protection CSP contre le XSS.
- 'unsafe-eval' : Autorise l'utilisation de fonctions d'évaluation de code dynamique comme
eval()etFunction(). Ă utiliser avec une extrĂȘme prudence car cela introduit des risques de sĂ©curitĂ© importants. - 'unsafe-hashes' : Autorise les gestionnaires d'Ă©vĂ©nements en ligne spĂ©cifiques ou les balises <style> qui correspondent Ă un hachage spĂ©cifiĂ©. NĂ©cessite la prise en charge par le navigateur. Ă utiliser avec prudence.
- 'strict-dynamic' : Spécifie que la confiance explicitement accordée à un script présent dans le balisage, en l'accompagnant d'un nonce ou d'un hachage, sera propagée à tous les scripts chargés par ce script racine.
- data : Autorise les URI data: (par exemple, images en ligne codées en base64). à utiliser avec prudence.
- https:: Autorise le chargement de ressources via HTTPS depuis n'importe quel domaine.
- [hostname] : Autorise les ressources d'un domaine spécifique (par exemple, example.com). Vous pouvez également spécifier un numéro de port (par exemple, example.com:8080).
- [scheme]://[hostname]:[port] : Une URI entiÚrement qualifiée, autorisant les ressources du schéma, de l'hÎte et du port spécifiés.
Exemples pratiques de CSP
Jetons un Ćil Ă quelques exemples pratiques d'en-tĂȘtes CSP :
Exemple 1 : CSP de base avec 'self'
Cette politique autorise les ressources uniquement depuis la mĂȘme origine :
Content-Security-Policy: default-src 'self'
Exemple 2 : Autoriser les scripts d'un domaine spécifique
Cette politique autorise les scripts de votre propre domaine et d'un CDN de confiance :
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Exemple 3 : Désactiver les scripts et styles en ligne
Cette politique refuse les scripts et styles en ligne, ce qui constitue une défense solide contre le XSS :
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Important : La désactivation des scripts en ligne nécessite de refactoriser votre HTML pour déplacer les scripts en ligne vers des fichiers externes.
Exemple 4 : Utilisation de nonces pour les scripts en ligne
Si vous devez utiliser des scripts en ligne, utilisez des nonces (jetons cryptographiquement alĂ©atoires Ă usage unique) pour autoriser des blocs de scripts en ligne spĂ©cifiques. C'est plus sĂ»r que 'unsafe-inline'. Le serveur doit gĂ©nĂ©rer un nonce unique pour chaque requĂȘte et l'inclure Ă la fois dans l'en-tĂȘte CSP et dans la balise <script>.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Note : N'oubliez pas de gĂ©nĂ©rer un nouveau nonce pour chaque requĂȘte. Ne rĂ©utilisez pas les nonces !
Exemple 5 : Utilisation de hachages pour les styles en ligne
Semblable aux nonces, les hachages peuvent ĂȘtre utilisĂ©s pour autoriser des blocs de <style> en ligne spĂ©cifiques. Ceci est fait en gĂ©nĂ©rant un hachage SHA256, SHA384 ou SHA512 du contenu du style.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Note : Les hachages sont moins flexibles que les nonces car toute modification du contenu du style invalidera le hachage.
Exemple 6 : Signalement des violations de CSP
Pour surveiller les violations de CSP, utilisez la directive report-uri ou report-to :
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Vous devrez Ă©galement configurer l'en-tĂȘte Report-To. L'en-tĂȘte Report-To dĂ©finit un ou plusieurs groupes de rapports, qui spĂ©cifient oĂč et comment les rapports doivent ĂȘtre envoyĂ©s.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Test et déploiement de la CSP
La mise en Ćuvre de la CSP nĂ©cessite une planification et des tests minutieux. Commencez par une politique restrictive et assouplissez-la progressivement si nĂ©cessaire. Utilisez l'en-tĂȘte Content-Security-Policy-Report-Only pour tester votre politique sans bloquer les ressources. Cet en-tĂȘte signale les violations sans appliquer la politique, vous permettant d'identifier et de corriger les problĂšmes avant de dĂ©ployer la politique en production.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analysez les rapports gĂ©nĂ©rĂ©s par le navigateur pour identifier toute violation et ajustez votre politique en consĂ©quence. Une fois que vous ĂȘtes convaincu que votre politique fonctionne correctement, dĂ©ployez-la Ă l'aide de l'en-tĂȘte Content-Security-Policy.
Bonnes pratiques pour la CSP
- Commencez par un default-src : Définissez toujours un
default-srcpour établir une politique de base. - Soyez spécifique : Utilisez des directives et des mots-clés de liste de sources spécifiques pour limiter la portée de votre politique.
- Ăvitez 'unsafe-inline' et 'unsafe-eval' : Ces mots-clĂ©s affaiblissent considĂ©rablement la CSP et doivent ĂȘtre Ă©vitĂ©s dans la mesure du possible.
- Utilisez des nonces ou des hachages pour les scripts et styles en ligne : Si vous devez utiliser des scripts ou des styles en ligne, utilisez des nonces ou des hachages pour autoriser des blocs de code spécifiques.
- Surveillez les violations de CSP : Utilisez la directive
report-urioureport-topour surveiller les violations de CSP et ajuster votre politique en consĂ©quence. - Testez minutieusement : Utilisez l'en-tĂȘte
Content-Security-Policy-Report-Onlypour tester votre politique avant de la déployer en production. - Itérez et affinez : La CSP n'est pas une configuration unique. Surveillez et affinez continuellement votre politique pour vous adapter aux changements de votre application et au paysage des menaces.
Qu'est-ce que le Cross-Origin Resource Sharing (CORS) ?
Le Cross-Origin Resource Sharing (CORS) est un mĂ©canisme qui permet aux pages web d'une origine (domaine) d'accĂ©der Ă des ressources d'une origine diffĂ©rente. Par dĂ©faut, les navigateurs appliquent une Same-Origin Policy, qui empĂȘche les scripts de faire des requĂȘtes vers une origine diffĂ©rente de celle d'oĂč provient le script. Le CORS offre un moyen de relĂącher sĂ©lectivement cette restriction, permettant les requĂȘtes cross-origin lĂ©gitimes tout en se protĂ©geant contre les attaques malveillantes.
Comprendre la Same-Origin Policy
La Same-Origin Policy est un mĂ©canisme de sĂ©curitĂ© fondamental qui empĂȘche un script malveillant d'un site web d'accĂ©der Ă des donnĂ©es sensibles sur un autre site web. Une origine est dĂ©finie par le schĂ©ma (protocole), l'hĂŽte (domaine) et le port. Deux URL ont la mĂȘme origine si et seulement si elles ont le mĂȘme schĂ©ma, le mĂȘme hĂŽte et le mĂȘme port.
Par exemple :
https://www.example.com/app1/index.htmlethttps://www.example.com/app2/index.htmlont la mĂȘme origine.https://www.example.com/index.htmlethttp://www.example.com/index.htmlont des origines diffĂ©rentes (schĂ©ma diffĂ©rent).https://www.example.com/index.htmlethttps://sub.example.com/index.htmlont des origines diffĂ©rentes (hĂŽte diffĂ©rent).https://www.example.com:8080/index.htmlethttps://www.example.com:80/index.htmlont des origines diffĂ©rentes (port diffĂ©rent).
Comment fonctionne le CORS
Lorsqu'une page web effectue une requĂȘte cross-origin, le navigateur envoie d'abord une requĂȘte "preflight" au serveur. La requĂȘte preflight utilise la mĂ©thode HTTP OPTIONS et inclut des en-tĂȘtes qui indiquent la mĂ©thode HTTP et les en-tĂȘtes que la requĂȘte rĂ©elle utilisera. Le serveur rĂ©pond ensuite avec des en-tĂȘtes qui indiquent si la requĂȘte cross-origin est autorisĂ©e.
Si le serveur autorise la requĂȘte, il inclut l'en-tĂȘte Access-Control-Allow-Origin dans la rĂ©ponse. Cet en-tĂȘte spĂ©cifie les origines qui sont autorisĂ©es Ă accĂ©der Ă la ressource. Le navigateur poursuit ensuite avec la requĂȘte rĂ©elle. Si le serveur n'autorise pas la requĂȘte, il n'inclut pas l'en-tĂȘte Access-Control-Allow-Origin, et le navigateur bloque la requĂȘte.
En-tĂȘtes CORS : Un examen dĂ©taillĂ©
Le CORS repose sur des en-tĂȘtes HTTP pour communiquer entre le navigateur et le serveur. Voici les principaux en-tĂȘtes CORS :
- Access-Control-Allow-Origin : SpĂ©cifie les origines autorisĂ©es Ă accĂ©der Ă la ressource. Cet en-tĂȘte peut contenir une origine spĂ©cifique (par exemple,
https://www.example.com), un joker (*), ounull. L'utilisation de*autorise les requĂȘtes de n'importe quelle origine, ce qui n'est gĂ©nĂ©ralement pas recommandĂ© pour des raisons de sĂ©curitĂ©. L'utilisation de `null` est appropriĂ©e uniquement pour les "rĂ©ponses opaques" telles que lorsque la ressource est rĂ©cupĂ©rĂ©e via le protocole `file://` ou un URI de donnĂ©es. - Access-Control-Allow-Methods : SpĂ©cifie les mĂ©thodes HTTP autorisĂ©es pour la requĂȘte cross-origin (par exemple,
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers : SpĂ©cifie les en-tĂȘtes HTTP autorisĂ©s dans la requĂȘte cross-origin. Ceci est important pour gĂ©rer les en-tĂȘtes personnalisĂ©s.
- Access-Control-Allow-Credentials : Indique si le navigateur doit inclure des informations d'identification (par exemple, cookies, en-tĂȘtes d'autorisation) dans la requĂȘte cross-origin. Cet en-tĂȘte doit ĂȘtre dĂ©fini sur
truepour autoriser les informations d'identification. - Access-Control-Expose-Headers : SpĂ©cifie quels en-tĂȘtes peuvent ĂȘtre exposĂ©s au client. Par dĂ©faut, seul un ensemble limitĂ© d'en-tĂȘtes est exposĂ©.
- Access-Control-Max-Age : SpĂ©cifie la durĂ©e maximale (en secondes) pendant laquelle le navigateur peut mettre en cache la requĂȘte preflight.
- Origin : Il s'agit d'un en-tĂȘte de requĂȘte envoyĂ© par le navigateur pour indiquer l'origine de la requĂȘte.
- Vary : Un en-tĂȘte HTTP gĂ©nĂ©ral, mais important pour le CORS. Lorsque `Access-Control-Allow-Origin` est gĂ©nĂ©rĂ© dynamiquement, l'en-tĂȘte `Vary: Origin` doit ĂȘtre inclus dans la rĂ©ponse pour indiquer aux mĂ©canismes de mise en cache que la rĂ©ponse varie en fonction de l'en-tĂȘte de requĂȘte `Origin`.
Exemples pratiques de CORS
Jetons un Ćil Ă quelques exemples pratiques de configurations CORS :
Exemple 1 : Autoriser les requĂȘtes d'une origine spĂ©cifique
Cette configuration autorise les requĂȘtes uniquement depuis https://www.example.com :
Access-Control-Allow-Origin: https://www.example.com
Exemple 2 : Autoriser les requĂȘtes de n'importe quelle origine (non recommandĂ©)
Cette configuration autorise les requĂȘtes de n'importe quelle origine. Ă utiliser avec prudence car cela peut introduire des risques de sĂ©curitĂ© :
Access-Control-Allow-Origin: *
Exemple 3 : Autoriser des mĂ©thodes et des en-tĂȘtes spĂ©cifiques
Cette configuration autorise les mĂ©thodes GET, POST et PUT, ainsi que les en-tĂȘtes Content-Type et Authorization :
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Exemple 4 : Autoriser les informations d'identification
Pour autoriser les informations d'identification (par exemple, les cookies), vous devez définir Access-Control-Allow-Credentials sur true et spécifier une origine spécifique (vous ne pouvez pas utiliser * lors de l'autorisation des informations d'identification) :
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Vous devez Ă©galement dĂ©finir credentials: 'include' dans votre requĂȘte fetch/XMLHttpRequest JavaScript.
fetch('https://api.example.com/data', {
credentials: 'include'
})
RequĂȘtes Preflight CORS
Pour certains types de requĂȘtes cross-origin (par exemple, les requĂȘtes avec des en-tĂȘtes personnalisĂ©s ou des mĂ©thodes autres que GET, HEAD ou POST avec Content-Type de application/x-www-form-urlencoded, multipart/form-data ou text/plain), le navigateur envoie une requĂȘte preflight utilisant la mĂ©thode OPTIONS. Le serveur doit rĂ©pondre Ă la requĂȘte preflight avec les en-tĂȘtes CORS appropriĂ©s pour indiquer si la requĂȘte rĂ©elle est autorisĂ©e.
Voici un exemple de requĂȘte et de rĂ©ponse preflight :
RequĂȘte Preflight (OPTIONS) :
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Réponse Preflight (200 OK) :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
L'en-tĂȘte Access-Control-Max-Age spĂ©cifie la durĂ©e pendant laquelle le navigateur peut mettre en cache la rĂ©ponse preflight, rĂ©duisant ainsi le nombre de requĂȘtes preflight.
CORS et JSONP
JSON with Padding (JSONP) est une technique plus ancienne pour contourner la Same-Origin Policy. Cependant, JSONP prĂ©sente des risques de sĂ©curitĂ© importants et doit ĂȘtre Ă©vitĂ© au profit du CORS. JSONP repose sur l'injection de balises <script> dans la page, ce qui peut exĂ©cuter du code arbitraire. Le CORS offre un moyen plus sĂ»r et plus flexible de gĂ©rer les requĂȘtes cross-origin.
Bonnes pratiques pour le CORS
- Ăvitez d'utiliser * : Ăvitez d'utiliser le joker (*) dans l'en-tĂȘte
Access-Control-Allow-Origin, car il autorise les requĂȘtes de n'importe quelle origine. SpĂ©cifiez plutĂŽt l'origine spĂ©cifique autorisĂ©e Ă accĂ©der Ă la ressource. - Soyez spĂ©cifique avec les mĂ©thodes et les en-tĂȘtes : SpĂ©cifiez les mĂ©thodes HTTP et les en-tĂȘtes exacts autorisĂ©s dans les en-tĂȘtes
Access-Control-Allow-MethodsetAccess-Control-Allow-Headers. - Utilisez Access-Control-Allow-Credentials avec prudence : N'activez
Access-Control-Allow-Credentialsque si vous avez besoin d'autoriser les informations d'identification (par exemple, les cookies) dans les requĂȘtes cross-origin. Soyez conscient des implications de sĂ©curitĂ© de l'autorisation des informations d'identification. - SĂ©curisez vos requĂȘtes preflight : Assurez-vous que votre serveur gĂšre correctement les requĂȘtes preflight et renvoie les en-tĂȘtes CORS corrects.
- Utilisez HTTPS : Utilisez toujours HTTPS à la fois pour l'origine et pour les ressources auxquelles vous accédez cross-origin. Cela aide à se protéger contre les attaques de type man-in-the-middle.
- Vary: Origin : Si vous gĂ©nĂ©rez dynamiquement l'en-tĂȘte `Access-Control-Allow-Origin`, incluez toujours l'en-tĂȘte `Vary: Origin` pour Ă©viter les problĂšmes de mise en cache.
CSP et CORS en pratique : une approche combinée
Bien que la CSP et le CORS traitent tous deux des problÚmes de sécurité, ils fonctionnent à des couches différentes et offrent une protection complémentaire. La CSP se concentre sur la prévention du chargement de contenu malveillant par le navigateur, tandis que le CORS se concentre sur le contrÎle des origines qui peuvent accéder aux ressources sur votre serveur.
En combinant la CSP et le CORS, vous pouvez crĂ©er une posture de sĂ©curitĂ© plus robuste pour vos applications web. Par exemple, vous pouvez utiliser la CSP pour restreindre les sources Ă partir desquelles les scripts peuvent ĂȘtre chargĂ©s, et le CORS pour contrĂŽler quelles origines peuvent accĂ©der Ă vos points d'API.
Exemple : Sécuriser une API avec CSP et CORS
Supposons que vous ayez une API hĂ©bergĂ©e sur https://api.example.com que vous souhaitez rendre accessible uniquement depuis https://www.example.com. Vous pouvez configurer votre serveur pour renvoyer les en-tĂȘtes suivants :
En-tĂȘtes de rĂ©ponse API (https://api.example.com) :
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
Et vous pouvez configurer votre site web (https://www.example.com) pour utiliser l'en-tĂȘte CSP suivant :
En-tĂȘte CSP du site web (https://www.example.com) :
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Cette politique CSP permet au site web de charger des scripts et de se connecter Ă l'API, mais l'empĂȘche de charger des scripts ou de se connecter Ă d'autres domaines.
Conclusion
La Content Security Policy (CSP) et le Cross-Origin Resource Sharing (CORS) sont des outils essentiels pour renforcer la sécurité de vos applications frontend. En configurant soigneusement la CSP et le CORS, vous pouvez réduire considérablement le risque d'attaques XSS, d'attaques par injection de données et d'autres vulnérabilités de sécurité. N'oubliez pas de commencer par une politique restrictive, de tester minutieusement et de surveiller et affiner continuellement votre configuration pour vous adapter aux changements de votre application et au paysage évolutif des menaces. En donnant la priorité à la sécurité frontend, vous pouvez protéger vos utilisateurs et assurer l'intégrité de vos applications web dans le monde numérique de plus en plus complexe d'aujourd'hui.