Budgets du BFF par visiteur
Le BFF limite les tentatives avant de lire ou valider leur contenu et avant tout appel backend. Une tentative invalide consomme donc aussi le budget. Les compteurs sont indépendants par adresse visiteur et opération :
| Opération | Routes POST | Budget |
|---|---|---|
| Connexion | /login |
8 tentatives / 15 minutes |
| MFA | /login/verify, /login/setup |
5 tentatives / 5 minutes, partagées entre les deux actions |
| Contact | /api/contact-requests |
5 tentatives / 10 minutes |
| Réservation | /api/booking-requests |
5 tentatives / 10 minutes |
Les variantes de langue appellent les mêmes actions. Les dépassements renvoient HTTP 429, Retry-After en secondes et Cache-Control: no-store. Les actions affichent un message français ; avec use:enhance, le transport JSON SvelteKit encode le statut 429 dans son enveloppe failure (HTTP 200), conformément au protocole des actions ; les API conservent le code rate_limited déjà exploité par le client. Une adresse absente ou invalide produit HTTP 503 plutôt qu’un repli sur un compteur commun au proxy. Les adresses IPv6 natives partagent un budget par préfixe /64 pour empêcher la rotation des identifiants d’interface. Les IPv4, y compris leurs représentations IPv6 mappées, restent limitées par adresse.
Chaîne de confiance requise
Section intitulée « Chaîne de confiance requise »Pour les images Docker Harmony, ADDRESS_HEADER=cf-connecting-ip configure getClientAddress() de l’adapter Node. Le code du limiteur ne lit jamais X-Forwarded-For, X-Real-IP ou directement un en-tête de la requête. Sans configuration de proxy, le développement local utilise l’adresse de la connexion.
Cette configuration n’est sûre qu’avec Cloudflare → Traefik → BFF :
- Cloudflare remplace
CF-Connecting-IPpar l’adresse du visiteur ; Traefik doit préserver ce champ. - Le pare-feu de l’origine doit autoriser HTTP/HTTPS uniquement depuis les plages Cloudflare à jour ; ne pas publier le port 3000 des conteneurs web. Les accès du réseau Docker et du VPS sont des accès de confiance et doivent rester restreints.
- Ne pas exposer la même image directement sur Internet avec cet en-tête activé. Pour une autre topologie, configurer et vérifier le proxy avant d’activer la confiance d’en-tête ; ne pas prendre arbitrairement la première entrée de
X-Forwarded-For. - Ne pas activer la suppression des en-têtes d’adresse visiteur ou le remplacement IPv6 par Pseudo IPv4 sans adapter la configuration. Les Workers pouvant influencer l’adresse de sous-requêtes sont également des composants de confiance à contrôler.
Le 13 octobre 2026, la lecture du VPS a confirmé Traefik sur 80/443 et les conteneurs web production/staging avec un port 3000 interne, sans publication hôte. Le filtrage Ionos des sources HTTP a été appliqué dans backend #121. Cette preuve ne garantit pas l’identité de la zone Cloudflare ; l’authentification d’origine spécifique reste suivie dans ce ticket. Aucun paramètre de production n’est modifié par cette PR : l’image embarque le réglage à son prochain déploiement autorisé. Vérifier les éventuelles surcharges Dokploy de ADDRESS_HEADER avant ce déploiement.
Portée et suivi
Section intitulée « Portée et suivi »Les fenêtres sont fixes à partir de la première tentative, en mémoire d’un processus. La table est bornée à 10 000 couples adresse/opération, nettoie les entrées expirées et refuse de nouveaux couples lorsqu’elle est pleine ; elle n’évince jamais une entrée encore active. Les compteurs sont réinitialisés au redémarrage et ne sont pas partagés entre réplicas. Les visiteurs d’une même IPv4 publique ou d’un même préfixe IPv6 /64 partagent un budget. Ajouter un stockage partagé avant une montée à plusieurs réplicas ; ces limites ne remplacent ni les protections par compte ni le WAF.
Le protocole de backend #116 permet désormais au backend de retrouver le budget du visiteur après contrôle du BFF, sans relever les limites. La récupération de mot de passe conserve son limiteur dédié et ses protections backend.
Validation : make verify, puis E2E_VISITOR_LIMITS=1 make e2e E2E_ARGS='--config playwright.visitor-limits.config.ts' après build. La recette utilise deux proxys locaux qui écrasent les en-têtes d’adresse pour simuler deux visiteurs, et vérifie les tentatives invalides, l’indépendance des budgets, les 429 et les en-têtes usurpés. Aucun appel au backend de production n’est nécessaire.
Retour arrière : revenir à l’image précédente et à sa configuration d’adresse ; conserver Access et le filtrage d’origine. Ne pas assouplir les limites backend pour compenser une configuration d’adresse incorrecte.
Sources : adapter Node SvelteKit, en-têtes Cloudflare et cas Workers.
Identité signée vers le backend (#116)
Section intitulée « Identité signée vers le backend (#116) »Les changements Web et Backend du ticket #116 doivent être livrés ensemble : déployer le support backend d’abord, puis le BFF, et configurer la même clé privée HARMONY_BFF_VISITOR_KEY de 64 caractères hexadécimaux sur les deux services. Utiliser une clé aléatoire dédiée par environnement, conservée dans le gestionnaire de secrets ; ne jamais la publier dans une variable PUBLIC_, le navigateur ou un fichier versionné. Aucun paramètre de production n’est modifié par ces changements.
Après admission par le limiteur de la requête courante, le transport serveur signe l’adresse canonique, la méthode POST, la route backend et l’horodatage. Le champ X-Harmony-BFF-Visitor est produit par le serveur ; toute valeur entrante est remplacée. Le backend vérifie HMAC-SHA256 et accepte la preuve pendant 60 secondes (tolérance future de 5 secondes). Le BFF ne suit pas les redirections des appels signés. Seuls les appels login, TOTP confirm/verify, contact et réservation sont concernés ; les autres appels ne reçoivent pas de preuve.
Le backend conserve 8 connexions / 15 minutes par adresse et par email, 10 vérifications MFA / 5 minutes par adresse avec protections atomiques du challenge, 5 soumissions / 10 minutes par adresse et 3 / heure par email pour chacun des formulaires. Les IPv6 sont regroupées par /64 comme dans le BFF. Les preuves absentes, falsifiées, périmées, dupliquées ou liées à une autre route retombent sur le budget d’accès direct ; elles ne donnent aucun droit d’accès. Sans clé commune correctement configurée, le comportement sécurisé précédent subsiste mais les visiteurs partagent encore le budget de l’adresse BFF.
La clé autorise le BFF à attester les adresses ; restreindre les accès au serveur, assurer la chaîne Cloudflare → Traefik → BFF, synchroniser les horloges et utiliser HTTPS vers un backend externe ou un réseau interne restreint. Ne pas journaliser les preuves. Révoquer cette confiance en retirant ou renouvelant la clé des deux côtés. Les compteurs restent en mémoire d’un seul processus ; coordonner les compteurs avant plusieurs réplicas. La recette locale prouve le protocole, pas la configuration Cloudflare/Dokploy en production.
Le contrat détaillé est dans docs/bff-visitor-budgets.md du dépôt backend. Recette croisée : backend local migré/seedé et E2E_BFF_VISITOR_IDENTITY=1 make e2e E2E_ARGS='--config=playwright.bff-visitor.config.ts', avec la même clé privée de test sur les deux services et API_BASE_URL dirigé vers ce backend. Les deux proxys locaux écrasent l’adresse de confiance ; le test épuise A, vérifie B et conserve la limitation d’un accès direct avec preuve forgée.