Les formulaires de contact, endpoints de connexion et APIs publiques sont des cibles fréquentes d’abus : spam, force brute, scraping et envois automatisés. Une protection efficace combine plusieurs couches ; aucune seule ne suffit.
Cet article décrit une approche en couches pour protéger formulaires et endpoints dans des applications Astro, Laravel et Node.js — le même modèle que ce portfolio utilise en production.
Couches de protection
- Rate limiting : limiter les requêtes par IP sur une fenêtre de temps.
- Honeypot : champ caché que les bots remplissent et pas les humains.
- Form timing : détecter les envois plus rapides qu’un humain (< 3,5 s).
- Origin check : valider Origin/Referer en production.
- Validation par schémas : Zod ou équivalent côté serveur.
- Sanitisation : nettoyer les inputs avant traitement ou stockage.
- CAPTCHA optionnel : Cloudflare Turnstile quand le volume le justifie.
Rate limiting
À appliquer sur les endpoints publics sensibles :
- Connexion et inscription : 5 tentatives par IP par minute.
- Réinitialisation de mot de passe : 3 par IP par heure.
- Formulaire de contact : 5 par IP par minute.
- APIs sans authentification : selon le cas d’usage.
Implémentation en mémoire pour un seul processus ; Redis avec plusieurs réplicas. Répondre avec 429 Too Many Requests et header Retry-After.
Honeypot
Champ caché en CSS (display: none ou position: absolute; left: -9999px). Les bots le remplissent automatiquement ; les humains ne le voient pas. S’il arrive avec une valeur, rejeter silencieusement (répondre 200 sans traiter, pour ne pas alerter le bot).
Form timing
Enregistrer un timestamp au rendu du formulaire (champ caché ou session). À la réception du POST, rejeter si le délai est inférieur à 3–4 secondes. Les bots envoient instantanément ; les humains prennent au moins quelques secondes.
Validation côté serveur
Schémas avec Zod (ou équivalent) sur chaque endpoint API :
- Types stricts : email comme email, téléphone formaté, longueur max.
- Champs requis vs optionnels explicites.
- Rejeter les payloads avec champs inattendus (strip ou reject).
- Messages d’erreur génériques au client ; détail uniquement dans les logs serveur.
Sanitisation
- Retirer le HTML des champs texte brut.
- Normaliser espaces et caractères de contrôle.
- Tronquer les chaînes qui dépassent la longueur max.
- Ne jamais interpoler l’input utilisateur dans des requêtes SQL ou templates sans échappement.
Origin check
En production, valider que le header Origin ou Referer correspond au domaine du site. Rejeter les requêtes de domaines inconnus. Pas infaillible (peut être falsifié), mais filtre les bots basiques et scripts cross-origin.
Cloudflare Turnstile
Quand le volume de spam justifie une friction supplémentaire, Turnstile de Cloudflare est léger et respectueux de la vie privée. Configuré avec TURNSTILE_SITE_KEY (public) et TURNSTILE_SECRET_KEY (serveur). Le serveur vérifie le token avant de traiter le formulaire.
Flux complet sur un endpoint
- Rate limit check → 429 si dépassé.
- Honeypot check → 200 silencieux si rempli.
- Form timing check → 400 si trop rapide.
- Origin check → 403 si origine invalide.
- Turnstile verification (si configuré) → 400 si invalide.
- Validation Zod → 400 avec erreurs de champ.
- Sanitisation → traiter.
Erreurs fréquentes
- Ne compter que sur la validation frontend.
- Rate limiting uniquement sur login, pas contact ni webhooks.
- Honeypot visible ou
tabindexaccessible (les lecteurs d’écran le remplissent). - Répondre 403 au honeypot (le bot apprend et s’adapte).
- Logger des payloads complets avec emails et téléphones (PII dans les logs).
- Rate limit en mémoire avec 3 réplicas (chacun a son propre compteur).
Voir aussi audit de sécurité, cybersécurité et APIs REST .