Comment implémenter des en-têtes sécurisés à l’aide de Cloudflare Workers ?



L’implémentation d’en-têtes de réponse HTTP robustes est une stratégie essentielle pour protéger votre site web contre des vulnérabilités courantes telles que les attaques XSS, le clickjacking, le sniffing MIME, l’injection intersite et bien d’autres. Cette pratique est largement reconnue et encouragée par des organisations de référence comme OWASP.

Si auparavant, je vous ai expliqué comment mettre en place ces en-têtes sur des serveurs web comme Apache, Nginx et IIS, il existe une méthode plus flexible pour ceux qui utilisent Cloudflare. Grâce à la puissance des Cloudflare Workers, vous pouvez manipuler les en-têtes de réponse HTTP directement au niveau de la plateforme Cloudflare.

Cloudflare Workers est une solution « serverless » qui vous permet d’exécuter du code JavaScript, C, C++ ou Rust, à proximité de vos visiteurs, grâce à un réseau de plus de 200 centres de données répartis dans le monde.

Cette approche offre une grande flexibilité, car vous pouvez appliquer des en-têtes de sécurité à l’ensemble de votre site, à des sous-domaines ou des URI spécifiques, en utilisant des expressions régulières pour définir les correspondances.

Pour cette démonstration, nous allons nous appuyer sur le code créé par Scott Helme.

Alors, commençons… 👨‍💻

  • Connectez-vous à votre compte Cloudflare et accédez à la section « Workers » (lien direct).
  • Copiez le contenu du fichier worker.js disponible sur GitHub et collez-le dans l’éditeur de script.
const securityHeaders = {
        "Content-Security-Policy": "upgrade-insecure-requests",
        "Strict-Transport-Security": "max-age=1000",
        "X-Xss-Protection": "1; mode=block",
        "X-Frame-Options": "DENY",
        "X-Content-Type-Options": "nosniff",
        "Referrer-Policy": "strict-origin-when-cross-origin"
    },
    sanitiseHeaders = {
        Server: ""
    },
    removeHeaders = [
        "Public-Key-Pins",
        "X-Powered-By",
        "X-AspNet-Version"
    ];

async function addHeaders(req) {
    const response = await fetch(req),
        newHeaders = new Headers(response.headers),
        setHeaders = Object.assign({}, securityHeaders, sanitiseHeaders);

    if (newHeaders.has("Content-Type") && !newHeaders.get("Content-Type").includes("text/html")) {
        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders
        });
    }

    Object.keys(setHeaders).forEach(name => newHeaders.set(name, setHeaders[name]));

    removeHeaders.forEach(name => newHeaders.delete(name));

    return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: newHeaders
    });
}

addEventListener("fetch", event => event.respondWith(addHeaders(event.request)));

Avant de sauvegarder, prenez un moment pour personnaliser les en-têtes en fonction des besoins spécifiques de votre site:

Content-Security-Policy: Vous pouvez définir une politique de sécurité précise en fonction de vos exigences.

Par exemple, si vous avez besoin d’autoriser l’inclusion de contenu via des iFrames à partir de plusieurs URL, vous pouvez configurer l’en-tête comme suit:

"Content-Security-Policy" : "frame-ancestors 'self' gf.dev toptips.fr.com",

Cette configuration permettrait l’intégration de contenu provenant de gf.dev, toptips.fr.com, ainsi que du site lui-même.

X-Frame-Options: Si vous devez afficher du contenu de votre site dans un iframe sur une page de votre propre site, vous pouvez définir la valeur sur « SAMEORIGIN ».

"X-Frame-Options": "SAMEORIGIN",

Server: Vous pouvez modifier ou supprimer l’en-tête du serveur pour des raisons de sécurité ou de personnalisation.

"Server" : "toptips.fr Server",

RemoveHeaders: Si vous souhaitez supprimer certains en-têtes, comme ceux qui pourraient révéler des informations sensibles sur votre serveur, vous pouvez les lister dans ce tableau.

let removeHeaders = [
	"Public-Key-Pins",
	"X-Powered-By",
	"X-AspNet-Version",
]

Ajout de nouveaux en-têtes: Vous pouvez ajouter vos propres en-têtes personnalisés dans la section securityHeaders. Par exemple:

let securityHeaders = {
	"Content-Security-Policy" : "frame-ancestors 'self' gf.dev toptips.fr.com",
	"Strict-Transport-Security" : "max-age=1000",
	"X-Xss-Protection" : "1; mode=block",
	"X-Frame-Options" : "SAMEORIGIN",
	"X-Content-Type-Options" : "nosniff",
	"Referrer-Policy" : "strict-origin-when-cross-origin",
    "Custom-Header"  : "Success",
}

Une fois que vous avez personnalisé vos en-têtes, nommez votre worker et cliquez sur « Enregistrer et déployer ».

Votre worker est maintenant prêt. Il faut ensuite l’appliquer au site où vous souhaitez implémenter les en-têtes. Je vais l’appliquer à mon site de test.

  • Accédez à votre tableau de bord Cloudflare et sélectionnez le site concerné.
  • Naviguez vers l’onglet « Workers » >> « Ajouter un itinéraire ».
  • Entrez l’URL à laquelle le worker doit être appliqué. Vous pouvez utiliser des expressions régulières ici.
  • Sélectionnez le worker que vous venez de créer et enregistrez.

Et voilà ! En quelques secondes, les en-têtes sont appliqués à votre site.

Voici un exemple de ce que cela donne dans les outils de développement de Chrome. Vous pouvez également utiliser un outil d’analyse d’en-tête HTTP pour vérifier vos paramètres.

Je note que l’en-tête du serveur ne se reflète pas ici, probablement parce que Cloudflare le remplace.

Comme vous pouvez le voir, l’ensemble du processus prend environ 15 minutes, sans nécessiter d’interruption de service ou de redémarrage du serveur comme cela serait le cas avec Apache ou Nginx. Si vous envisagez d’appliquer ces paramètres sur un site de production, il est préférable de commencer par les tester dans un environnement de test, ou sur des pages de test spécifiques, pour vérifier les résultats. Une fois satisfait, vous pourrez appliquer ces en-têtes à l’ensemble de votre site en production.

C’est excellent!

Merci à Scott pour le code.