Le fil

101 index.html
De L4 à L7

Épopée d'une saine paranoïa.

Au départ, un besoin simple : je n'aime pas particulièrement "le design front". Le HTML et le CSS ne sont pas les technologies que je préfère. Une envie : générer une page index.html avec un LLM "pour voir". Je pars d'un setup BareMetal / Proxmox / Firewall VM / Reverse Proxy que j'exploite depuis 2010 — mais sans réelle maîtrise de la sécurité Layer 7 jusqu'à ce que ce projet m'oblige à la construire.

De recherches en découvertes, de l'analyse à l'intégration ... Itinéraire d'un clic.

Ép. I

Le point de départ : un besoin modeste

En Belgique, la Taxe sur les Opérations de Bourse se déclare et se paye manuellement chaque mois. Comme investisseur chez Trade Republic, je recevais un PDF et je devais calculer la taxe due, générer un virement SEPA avec la bonne référence, envoyer un mail à l'administration fiscale. Irritant, répétitif, parfait pour un premier lab.

Avec mon ami, on a décidé de faire un petit service qui lit le PDF, calcule la taxe, produit le QR code SEPA et prépare le mail. Rien d'ambitieux au départ.

3 clics et c'est parti

Ép. II

Le premier problème rencontré

Mise en ligne du formulaire d'inscription, je m'arrête et le regarde. Si quelqu'un tombe là-dessus en attaquant, il peut créer des milliers de comptes par seconde jusqu'à ce que la base tombe. Les champs peuvent recevoir autre chose que ce qui est prévu — et même avec de l'escaping JavaScript, ça se contourne côté client.

J'ai écrit la partie serveur en API REST et j'ai regardé le résultat : les endpoints étaient exposés, un token d'accès distribué à la demande, aucune restriction réelle à part un capcha et de l'escaping, vérification de token dans l'API.

L3-L5, je connaissais. Le layer 7, non. Et je ne voulais pas construire quelque chose que je savais fragile.

Ce n'est pas à l'API à gérer la sécurité

Ép. III

Le moment où j'ai réalisé que le problème était plus grand

Pendant que je réfléchissais à comment protéger le service, j'ai commencé à utiliser des LLM pour corriger et ajouter des parties au frontend. J'ai vu la facilité de création et d'édition de l'HTML, du CSS, du Javascript. Et aussi les limites : de plus en plus de gens vont construire un frontend sans maîtriser le stack sous-jacent — ce qu'on appelle aujourd'hui le vibe coding. Ces personnes ont besoin de mettre leurs applications en ligne, mais elles n'ont pas les moyens de réfléchir à la sécurité derrière. Je venais moi-même de découvrir que c'était difficile, en partant pourtant avec des bases techniques solides.

Je me suis dit : si je construis les couches de protection correctement pour notre petit service, tant qu'a faire, autant construire quelque chose de plus général — une plateforme où d'autres développeurs peuvent déployer leurs applications sans avoir à s'occuper de la sécurité. Pas pour vendre ça demain, mais pour que la question soit résolue proprement pour nous, et potentiellement pour d'autres plus tard, mes amis, leurs enfants (surtout).

1 clic publish, 0 tracas

Ép. IV

À partir de là : goto( R&DfD )

Research and Destroy for Development : Pour chaque niveau d'attaque possible, je recherche de la couche qui le bloque, analyse et études des solutions existantes, itération sur "sélection / tests / desctruction / remontage / documentation". Puis passage à la couche suivante. Dans l'ordre logique d'une requête HTTP, depuis le clic jusqu'à la réponse reçue par le navigateur, du point de vue de la requête, de l'infra, de l'attaquant pour empêcher plutôt qu'interdire ou bloquer.

Toujours en gardant à l'esprit les conséquences possibles d'une intrusion, limitant les scopes le plus possible pour que même en cas d'incident, il soit le plus limitant possible en surface d'attaque. Ne pas penser avoir "supprimé" la surface, chercher à la "limiter".

La "black team" est acharnée, sans doute bien plus skillée que moi et très, très inventive.

On ne supprime pas la surface, on la limite au maximum

Ép. V

Kong — d'abord ralentir

Avant tout, il faut pouvoir imposer un rythme. Une limite absolue. Je découvre les API gateway. Très vite, Kong s'impose comme une référence. Konga comme projet open-source pour l'interface web. Je n'en ai pas besoin.

Création des routes, des policy rating, application des plugins. Le token d'autorisation est sorti de l'API. Echange de header entre Kong et l'API pour l'indentification des requêtes et des users.

Mise en place de routes séparées pour l'inscription hors authentification et pour les endpoints authentifiés. Découverte de reddis, mise en place de rotation de token, du JWT amenant à la couche d'après.

Contraindre l'attaquant à un budget fini d'appels

Ép. VI

Keycloak — ensuite savoir qui parle, et dans quel périmètre

Il m'a fallait une manière plus efficace d'authentifier un utilisateur sur base uniquement de son token qu'il devrait à chaque fois renvoyer dans toutes ses requêtes. J'y ai vu une possibilité d'ursurpation d'identité possible. Il fallait que je protège "un admin" d'être le seul à être lui.

J'ai découvert les Identity Provider à cet étape dont la liste n'est pas ultra longue. J'aime l'open-source, mais il me fallait un projet mature pour cela. Comparaison avec Authelia, qui est plus simple et plus populaire pour du homelab. Toujours dans l'idée d'élargir un jour, je voulais du multi-realm : chaque site hébergé devait avoir son propre espace d'utilisateurs, isolé des autres, sans fuite ni usurpation inter-tenant.

J'ai pu lier keycloak à kong, et m'assurer que chaque requête était bien faite par la bonne personne. Keycloack fournit une page d'inscriptions propre.

J'ai découvert OIDC à ce moment-là. Authelia ne couvrait pas ce cas. Keycloak, oui.

Après avoir pensé à ce qu'il se passait quand la requête arrivait au serveur, je reviens à l'étape 1 de ma réflexion : le clic.

Quelques longues soirées/nuits plus tard de lab, je me rends compte de la puissance du javascript, du XSS, d'un localstorage mal géré, de la mine d'or des cookies, des liens entre chrome et android ...

On peut forger une trame ? Quid d'une "déformation controlée" d'une requête ?

Ép. VII

Mailu — pour tenir le mail en multi-domaine

Au début de l'aventure, pas de recherche sur les emails. Mailcow était en place. Mais lourd, grosse stack, pas pratique en multi-domaine. Mailu est simple, s'installe en une matinée et fournit les records DNS nécessaires.

À cette occasion, j'ai acheté api-cultor.com en prévision d'une activité d'hosting éventuelle, et j'ai migré mon mail personnel dessus.

Cultivons joyeusement des API

Ép. VIII

OAuth2 BFF — obfusquer les tokens et contraindre l'origine

Le pattern Backend-for-Frontend : à partir de maintenant, les tokens ne quittent jamais le serveur, le navigateur ne voit qu'une session chiffrée côté backend. L'exécution depuis une origine autre que la page elle-même devient "structurellement impossible".

Entre les advanced settings des hosts de Nginx, les instructions du docker-compose.yml, les formats requis pour les cookies secret. Les clients-id et client-secret de "client keycloak" prennent sens.

Cette couche a été la plus difficile à configurer. J'ai avancé par essais-erreur plus que par construction élégante. Mais je ne lâche pas, et ça tourne aujourd'hui.

Le pattern OAuth2 est respecté

Ép. IX

CrowdSec — apprendre collectivement

Mailu est bien, mais à ce jour, je n'ai pas trouvé de manière élégante d'y mettre un MFA, ou de limiter le bruteforce de login. Je me suis donc renseigné sur les WAF, l'analyse comportementale des requêtes. Détection des les patterns malveillants détectés localement et partagés avec le réseau. Ceux détectés ailleurs protègent mon infra.

Un pour tous et tous pour un

Ép. X

Le résultat, pour le développeur applicatif

Le dev appelle sont API en url/me/nom-methode. C'est tout. Derrière, Kong rate-limite, Keycloak authentifie, le BFF protège les tokens, CrowdSec filtre le comportement, Mailu gère les mails transactionnels.

Le path de la page d'inscription lui est imposé en url/me/login. C'est la "route publique d'authentification" de kong pour le front basée sur certaines policy.

Le dev ne voit rien de tout cela. Il ne peut pas l'oublier ni le mal configurer. La sécurité est dans la plateforme, pas dans le code applicatif. S'il se trompe, cela ne fonctionne pas. Il ne voit jamais aucun token d'accès, ni son api, ni son front. Tout lui est inaccessible, à lui comme à tout le monde.

Une seule mission pour lui : le dev

Ép. XI

Autour de la pile applicative

Proxmox en bare-metal comme hyperviseur. OPNsense en routeur virtualisé. Nginx en reverse proxy. OVH Gravelines et Canada pour le backup multi-région. Docker et Docker Compose pour tout ce qui tourne en containers.

Ép. Annexe

Un agent IA auto-hébergé, isolé

Parce que l'IA est partout, et sans les LLM, je n'aurais pas pu réaliser cela aussi vite. Je vois cette technologie comme une formidable opportunité de concentration.

J'ai donc en parrallèle commencer la configuration d'agent IA personnel — via OpenClaw — pour simplifier ma vie et réduire le bruit.

Les enjeux de sécurité encouru par ces agents qui sillonnent le web sont gigantesques. Et je voulais cet agent "maitre de son système". Aussi, je l'ai déployé sur une machine dédiée, dans mon réseau local.

Objectif : interdire le LAN de le voir et lui interdire de voir le LAN. Réplication de la config que je maitrise bien : OPNsense et Proxmox, complètement isolé : accès internet oui, accès au reste du LAN non.

La démarche est cohérente avec le reste : je voulais pouvoir expérimenter avec un agent autonome sans que ses permissions débordent là où elles ne devraient pas être. Je pars du principe qu'il sera sujet à des attaques et limite la possiblité d'action d'un agent infecté.

Je passe progressivement à Ollama en local pour ne plus dépendre d'un modèle cloud. Historiquement sur Antropic qui l'interdit maintenant, je ne souhaite plus dépendre de solutions externes.

L'IA pas pour automatiser, mais émanciper.

Synthèse

Ma méthode

Je pars d'un objectif concret, même modeste. Je laisse les problèmes se présenter d'eux-mêmes plutôt que d'essayer de tout anticiper — parce que les vrais problèmes se découvrent en construisant, pas en réfléchissant. Je les résous dans leur ordre naturel. Je choisis chaque outil en le comparant à d'autres, pas en prenant le plus connu par défaut. J'apprends en cassant et en remontant, parce que c'est là que je comprends vraiment comment un système tient.

J'ai une pensée systémique qui me permet de visualiser les solutions apportées et de tester les distorsions possibles.

Ici, l'on est partis d'un outil fiscal personnel, et on a fini avec une plateforme qu'on peut proposer à des développeurs qui construisent vite mais ne veulent/peuvent pas gérer eux-mêmes la sécurité.

Coda

Apprendre, puis transmettre

Une dernière note, parce que c'est un fil qui traverse toutes mes expériences.

Au Microsoft Innovation Center Belgium, j'ai conçu des labs d'immersion client, animé des démonstrations live improvisées, formé des étudiants de hautes écoles, des professionnels en workshops, et des enfants en robotique Lego. Trois publics aux codes différents, une même exigence : transmettre un modèle, pas des procédures.

En cuisine, j'ai appris sur le tas, dans le mouvement. Mon premier jour de stage chez un chef étoilé, m'a vu plonger dans le bain événementiel immédiatement. Au cinquième jour, j'étais lâché en service. Ce n'est pas une manière de transmettre qui rassure sur le moment, mais quand il faut tout donner, je ne me retiens pas.

Dans mon poste actuel, j'introduis progressivement des pratiques que mes collègues n'utilisaient pas — reverse proxy, sécurité applicative, OAuth — je documente et explique les procédés découverts et mis en place.

C'est la même compétence, appliquée à des domaines différents : étudier, comprendre les mécanismes, pratiquer jusqu'à pouvoir reproduire, puis transmettre. Dans cet ordre.