[flaflix] — Flavien Sailliot, retour à l’accueil

Ce portfolio — un site statique durci

Site Astro 100 % statique, CSP stricte sans unsafe-inline, zéro traceur, déployé par GitLab CI sur mon VPS. Le site lui-même est un projet de sécurité.

en cours
  • Astro
  • CSS natif
  • GitLab CI
  • Debian
  • HTTPS
  • CSP
Chaîne de publication du portfolio : depuis mon poste, git push vers GitLab CI, qui détecte les secrets, construit le site statique et vérifie l'absence de code inline, puis le déploie par rsync sur SSH vers le VPS Debian. Sur le VPS, un utilisateur de déploiement restreint, le serveur web en HTTPS et les en-têtes de sécurité. Les visiteurs n'y accèdent qu'en HTTPS. Aucune base de données ni code exécuté côté serveur.
fig. 1 — schéma d’architecture (cliquer pour agrandir)

Contexte

Un portfolio de profil cyber qui serait lui-même mal sécurisé, ce serait un comble. J’ai donc traité ce site comme un projet à part entière : chaque choix technique est fait pour réduire la surface d’attaque, et vérifiable par n’importe qui.

Objectif

  • Présenter mes projets, mon parcours et mes writeups.
  • Viser la meilleure note sur securityheaders.com et Mozilla Observatory.
  • N’utiliser aucun traceur, aucun cookie, aucune ressource externe.
  • Automatiser entièrement la mise en ligne.

Architecture

Le site est 100 % statique : Astro génère des fichiers HTML, CSS et JavaScript au moment du build. Sur le serveur, il n’y a ni base de données, ni langage exécuté à chaque visite, ni interface d’administration : rien à injecter, rien à pirater de ce côté-là. Le serveur web se contente de servir des fichiers.

La mise en ligne passera par GitLab CI (en cours de mise en place) : à chaque git push, le pipeline cherchera des secrets oubliés dans le code, construira le site, vérifiera qu’aucun code inline ne s’y est glissé, puis le copiera sur le VPS avec un utilisateur dédié aux droits limités. La détection de secrets est déjà configurée.

Ce que j’ai fait

Une CSP stricte, sans unsafe-inline

La Content Security Policy indique au navigateur d’où il a le droit de charger des scripts et des styles. Ici : uniquement depuis le site lui-même, et jamais de code écrit directement dans la page. Même si quelqu’un réussissait à injecter du HTML, son script ne serait pas exécuté.

Ça impose de la rigueur :

  • aucun attribut style="…", aucun <script> inline, aucun onclick= ;
  • Astro est configuré pour toujours sortir le CSS dans des fichiers séparés ;
  • la coloration du code utilise des classes CSS (Prism) plutôt que des styles inline ;
  • chaque build est contrôlé : la moindre ligne inline dans le résultat est repérée.

La CSP sera envoyée en en-tête HTTP par le serveur, et non en balise <meta> : c’est plus complet, et c’est ce que notent les outils d’audit.

Zéro dépendance externe

Les polices sont auto-hébergées, il n’y a ni CDN, ni Google Fonts, ni statistiques de visite. Un visiteur ne contacte que ce serveur : aucune donnée ne part chez un tiers.

JavaScript facultatif

Tout le contenu est lisible sans JavaScript. Les scripts (terminal, thèmes, recherche) sont des améliorations : désactivez-les, le site fonctionne toujours. Le terminal écrit ses réponses avec textContent, jamais innerHTML : ce qu’on y tape ne peut pas devenir du HTML.

Accessibilité et performance

Contrastes AA vérifiés sur chacun des dix thèmes, navigation au clavier, lien d’évitement, animations coupées si le système le demande. Lighthouse : 100 en performance, accessibilité, bonnes pratiques et SEO.

Les brouillons ne fuient pas

Un projet ou un article marqué « brouillon » est visible sur mon poste, mais exclu du build : aucune page, aucun lien, ni dans le sitemap, ni dans le flux RSS. Même règle pour les textes encore à compléter.

Difficultés & solutions

Une page entièrement blanche

  • Problème : après l’ajout d’une séquence de démarrage animée, plus rien ne s’affichait. Page blanche, sans aucune erreur dans la console.
  • Diagnostic : en désactivant les éléments un par un, j’ai isolé la cause. Le script posait la classe boot sur la balise <html>, et une règle CSS .boot { display: none }, prévue pour l’écran de démarrage, s’appliquait aussi… à toute la page.
  • Solution : renommer la classe posée sur <html>.
  • Leçon : un sélecteur de classe ne sait pas à quel élément on pensait. Les classes d’état globales doivent avoir des noms qui ne peuvent pas entrer en collision.

Coloration du code et CSP

  • Problème : la coloration syntaxique par défaut d’Astro (Shiki) écrit des style="…" dans le HTML, que la CSP bloque.
  • Solution : passer à Prism, qui n’utilise que des classes, et écrire le thème de couleurs en CSS.
  • Leçon : une CSP stricte se décide au début d’un projet. L’ajouter à la fin, c’est découvrir tout ce qui l’enfreint.

Ce que j’ai appris

  • Concevoir avec une contrainte de sécurité dès le départ plutôt que de l’ajouter après.
  • Le fonctionnement réel d’une CSP et des en-têtes de sécurité HTTP.
  • L’amélioration progressive : un site qui marche d’abord sans rien, puis mieux avec.
  • Automatiser un déploiement avec le minimum de privilèges.

Prochaines étapes

  • Mise en ligne sur le VPS : serveur web, HTTPS, en-têtes de sécurité.
  • Pipeline GitLab CI complet, avec déploiement automatique.
  • Publier ici les notes obtenues sur securityheaders.com et Mozilla Observatory.

Ce terminal fonctionne : essayez help, ls, cd blog ou hint.