Content Security Policy (CSP) avec Kirby

L’année dernière, j’ai pris le temps d’améliorer la sécurité de mon site avec des entêtes HTTP.

En voulant mettre en place des règles CSP (politique de sécurité de contenu) avancées, je bloquais sur le tableau d’administration (panel) du site qui devenait inutilisable.

Il se trouve que Kirby permet de générer un nonce et de sécuriser ainsi les scripts en ligne utilisés dans le panel.

Par conséquent, il faut simplement déclarer les règles CSP en passant par le fichier de configuration du CMS1 et non dans le fichier .htaccess.

'ready' => function ($kirby) {
    header("Content-Security-Policy: […]");
  }

Pour définir mes règles CSP, je me suis aidée :

  1. de l’extension Laboratory (Content Security Policy CSP Toolkit),
  2. du Mozilla Observatory (section Content Security Policy Analysis),
  3. de l’article Déployer CSP : une approche en 5 étapes,
  4. et de Google CSP Evaluator.

Mes règles CSP détaillées

header("Content-Security-Policy: default-src 'none';  
connect-src 'self'; base-uri 'self';
style-src 'self'; font-src 'self'; img-src 'self' data:;
script-src 'self' 'unsafe-inline' 'nonce-" . $kirby->nonce() . "'; 
frame-ancestors 'none'; require-trusted-types-for 'script'")

Rappel important : la sécurité ne relève pas de mon domaine d’expertise. Je vous invite à ne jamais copier les exemples donnés sans les comprendre et les avoir testés.

Ne rien autoriser par défaut : default-src 'none'

Avec default-src 'none', je n’autorise rien par défaut. Vous ne passerez pas !

À ce stade, vous comprenez bien que tout est bloqué. Ça m’oblige à préciser le comportement de chaque directive qui en dépend (child-src, connect-src, font-src, img-src, media-src, object-src, script-src et style-src).

child-src, media-src et object-src héritent de la valeur de default-src.
Si un jour, je souhaite ajouter des médias audio ou vidéo, il faudra que je définisse media-src.

Autoriser le nécessaire

Un site sans rien du tout, c’est certainement conceptuel, mais ça ne sert pas à grand chose.

Pour accéder au tableau de bord, j’ai besoin de connect-src 'self' et de base-uri 'self'. J’autorise également les styles, images, polices, scripts hébergés chez moi.

  1. Pour les styles CSS (style-src 'self'), je m’interdis actuellement le style en ligne. Il n’est pas impossible qu’un jour je sois obligée de revenir sur cette exigence.
  2. En plus des images hébergées sur le site, j’ai besoin d'autoriser les data URI pour le panel Kirby, d’où le data:.
  3. Seuls les scripts hébergés chez moi et ceux en ligne avec le nonce généré par Kirby sont exécutés. La valeur 'unsafe-inline' est présente pour des raisons de compatibilité avec les vieux navigateurs, mais ignorée autrement.

Divers

J’empêche le site d’être encapsulé dans une iframe avec frame-ancestors 'none' et j’ai ajouté require-trusted-types-for 'script' sur les conseils de Google CSP Evaluator.

Conclusion

Une fois levée la problématique du panel Kirby, mettre en place des règles CSP exigeantes n’a pas été trop difficile. En effet, sur ce site, je pars de zéro.

Je m’efforce de bien faire les choses et de réduire au maximum les dépendances tierces non vérifiées. Je vois ces règles comme des protections contre la tentation de faire vite et sale. On verra si j’arrive à m’y tenir.

Je vous invite à tenter l’exercice sur vos nouveaux projets, c’est moins pénible2 que ce que je pensais :)

(Si vous voyez des erreurs ou des approximations dangereuses dans ce billet, n’hésitez pas à me les signaler.)


  1. Cf. la réponse de Bastian Allgeier sur Github. ↩︎

  2. Le travail de reprise de code que peut nécessiter la mise en place de CSP sur des projets avec de l’historique semble lui assez pharamineux (Franck a consacré plusieurs billets sur le sujet pour l’interface d’administration de Dotclear). Il semble préférable d’y aller progressivement dans ces cas là. ↩︎

Contact

Vous souhaitez réagir ? N’hésitez pas à m’écrire à contact@luce.carevic.eu.