Table des matières :
- Cloudflare Custom Rules : le vrai périmètre (et ce que ça n’est pas)
- Concevoir une politique WAF sur mesure : partir de la menace, pas du dashboard
- Écrire des Custom Rules propres : langage d’expression, champs utiles et pièges classiques
- Déployer sans casser la prod : ordre des règles, mode “log”, challenges et rollback
- Mesurer et investiguer : logs WAF, SIEM, métriques et corrélation (sinon vous pilotez à l’aveugle)
- Automatiser et gouverner : API, Terraform, GitOps… et un minimum de discipline
Cloudflare Custom Rules : le vrai périmètre (et ce que ça n’est pas)
Parlons clair : Cloudflare Custom Rules (souvent rangées sous “WAF custom rules” dans l’interface) ne sont pas un “WAF magique”. C’est un moteur de règles (Ruleset Engine) exécuté à l’edge, avant que votre applicatif n’ait le temps de dire “502”. L’idée : vous décrivez une condition (une expression) sur la requête HTTP et Cloudflare applique une action (bloquer, challenger, journaliser, bypasser un produit de sécurité, etc.). C’est plus souple que les règles managées, et plus dangereux si vous confondez “souple” avec “je vais tout autoriser en prod, YOLO”.
À ne pas confondre non plus avec les Managed Rules (OWASP, CMS, etc.) : ces dernières sont des signatures maintenues par Cloudflare, mises à jour pour vous (oui, comme des définitions antivirus… en mieux, et avec moins de pop-ups). Les Custom Rules, elles, sont votre responsabilité : vous écrivez la logique, vous la maintenez, vous assumez les faux positifs. Si vous cherchez un panorama plus large de la brique Cloudflare côté CDN, vous pouvez croiser avec ce retour d’expérience : « Cloudflare : notre avis sur cet opérateur CDN »
Enfin, une précision “terminologie qui change selon l’humeur des dashboards” : Cloudflare a historiquement eu des Firewall Rules (ancien moteur). Aujourd’hui, l’approche recommandée passe par des Rulesets et des phases d’exécution (par ex. des règles exécutées en httprequestfirewall_custom). Si vous avez un mix d’anciennes règles et de rulesets, faites une cartographie — sinon vous allez déboguer pendant des heures un comportement “inexplicable” (en réalité : deux moteurs qui se marchent dessus).
Deux points pratiques (souvent découverts après un incident) :
- Le périmètre est HTTP(S) : Custom Rules filtrent la requête au niveau HTTP. Elles ne “réparent” pas une logique métier vulnérable, une autorisation cassée, ou une API trop bavarde. Elles réduisent la surface et augmentent le coût de l’attaque.
- Tout dépend de la phase : selon où vous accrochez la règle (custom firewall, rate limiting, transform rules, etc.), les champs disponibles et l’impact diffèrent. La doc Cloudflare sur le Ruleset Engine est le bon référentiel pour comprendre le “pipeline” : documentation du Ruleset Engine
Concevoir une politique WAF sur mesure : partir de la menace, pas du dashboard
Écrire des règles WAF personnalisées sans modèle de menace, c’est comme configurer un firewall réseau “au feeling” : ça marche jusqu’au jour où ça ne marche plus. Commencez par l’inventaire des surfaces exposées : chemins sensibles (admin, login, graphql, webhooks), endpoints d’API, formulaires, upload, recherche interne, pages de paiement. Dans un e-commerce, l’attaque n’est pas seulement “SQLi” : c’est aussi l’énumération de comptes, le scraping de prix, les bots de scalping, et le bourrage de panier qui met votre stock à genoux.
Un bon cadre de départ reste l’OWASP Top 10 (et ses dérivés API). OWASP le résume très bien : « The OWASP Top 10 is a standard awareness document for developers and web application security. » (OWASP Top 10). Traduction : ce n’est pas une checklist de conformité pour commerciaux pressés, mais une base pour prioriser vos contrôles. Les Custom Rules Cloudflare sont parfaites pour traiter la partie “contrôle d’accès au périmètre HTTP” : méthodes interdites, endpoints non utilisés, user-agents connus pour être toxiques, pays/ASN incohérents avec votre business, etc.
Pour éviter la “politique WAF au doigt mouillé”, une méthode simple consiste à classer vos endpoints par valeur et par probabilité d’abus :
- Valeur élevée :
/login,/checkout,/account, endpoints de reset de mot de passe, endpoints d’admin, webhooks PSP/ERP/CRM. - Abus fréquent :
/search(scraping),/graphql(requêtes coûteuses), endpoints d’upload (malware / stockage abusif), formulaires (spam + injection), endpoints d’API non authentifiés.
Ensuite, associez à chaque zone une intention de contrôle, par exemple :
- Réduire le bruit (hygiène) : méthodes non supportées, chemins inexistants, UA manifestement automatisés.
- Augmenter le coût : challenge sur login en cas de signaux bots / réputation.
- Protection ciblée : allowlist stricte sur webhooks entrants et backoff sur endpoints coûteux.
Dernier point (souvent oublié parce que ça ne se voit pas dans un ticket Jira) : l’impact SEO/UX. Si votre règle challenge Googlebot ou bloque une route de rendu SSR, vous venez d’inventer le negative SEO maison. Une pratique saine : intégrer vos règles WAF dans votre démarche d’audit global (performance + sécurité + SEO) afin d’éviter d’optimiser un axe en sabotant l’autre. Sur ce sujet, l’article interne « Audit de site web : technique, SEO, UX et sécurité pour une roadmap » est un bon point de départ.
Enfin, un point “terrain” côté France/UE : la géolocalisation (ip.geoip.country) peut être utile (ex. activité anormale sur un service strictement B2B France), mais elle doit rester un signal, pas une vérité absolue. Dans la vraie vie :
- vos clients voyagent,
- certains FAI mobiles sortent via des points de présence variés,
- et une partie du trafic légitime passe par des egress cloud (VPN d’entreprise, SASE, etc.). Utilisez donc les règles “geo/ASN” plutôt en challenge qu’en block sur des parcours critiques, sauf cas très documenté.
Écrire des Custom Rules propres : langage d’expression, champs utiles et pièges classiques
Le moteur Cloudflare utilise un langage d’expression typé, lisible et… impitoyable si vous êtes approximatif. Une règle, c’est essentiellement :
- des attributs (ex.
http.request.uri.path,http.request.method,ip.src,cf.threat_score,cf.asnum,ip.geoip.country), - des opérateurs (
eq,ne,contains,matches,in, etc.), - et une action (
block,managed_challenge,js_challenge,challenge,log,skip, … selon produit/phase).
Le réflexe pro : partir d’un signal stable (chemin, méthode, host, content-type), puis affiner. Évitez les regex “attrape-tout” sur l’URL complète si une condition simple sur uri.path suffit.
Exemple basique (mais utile) : bloquer les méthodes qui n’existent pas chez vous sur le frontend public.
(http.request.method in {"TRACE" "TRACK" "CONNECT"})
C’est de l’hygiène. Ce n’est pas “la cybersécurité”. Mais ça supprime du bruit et réduit les angles bizarres.
Pour un e-commerce, un classique : durcir des endpoints admin connus, sans casser l’accès des équipes. Exemple : autoriser /admin uniquement depuis un set d’IP (VPN/bastion), et challenger le reste.
(http.request.uri.path starts_with "/admin") and not (ip.src in $CORP_VPN)
Deux détails importants : (1) utilisez des IP Lists Cloudflare (variables type $CORP_VPN) plutôt que de hardcoder 12 adresses dans une règle, sinon votre règle devient un fichier Excel. (2) préférez d’abord log ou managed_challenge avant block, surtout si /admin est parfois exposé via un SSO ou une redirection.
Champs et patterns qui “payent” en prod (sans vous piéger)
Sans chercher l’usine à gaz, quelques combinaisons sont particulièrement rentables :
- Toujours borner par le host quand vous avez plusieurs sites/Apps derrière une même zone (ou plusieurs environnements) :
http.host eq "www.exemple.com"ouin {"www…" "api…"}- Méthode + chemin, plutôt que seulement le chemin :
- une route peut être légitime en
GETmais dangereuse enPOST. - Content-Type pour limiter certains endpoints :
- ex. n’accepter
application/jsonsur une API, et challenger/loguer le reste. - Éviter les règles “négation totale” du style
not ip.src in $ALLOWLISTsans autre filtre : trop large, trop risqué.
Un piège fréquent : les regex. Une regex non bornée sur http.request.uri peut matcher des choses inattendues et créer des faux positifs massifs. Si vous utilisez matches, essayez de :
- borner avec
^/$si possible, - matcher
uri.pathplutôt que l’URI complète, - documenter pourquoi la regex existe (sinon personne n’osera y toucher).
Enfin, ne sous-estimez pas l’intérêt de cf.threat_score ou des signaux bot (si vous avez les produits Cloudflare associés). Sans tomber dans le délire “score-driven security”, c’est un bon gate pour déclencher un challenge sur des requêtes déjà jugées suspectes, en particulier sur des routes à forte valeur (auth, checkout, webhooks).
Un exemple “lisible” (à adapter selon votre app et vos seuils) : challenger uniquement les tentatives de login “suspectes” plutôt que tout le monde.
(http.request.uri.path eq "/login")
and (http.request.method eq "POST")
and (cf.threat_score ge 20)
Pour la sécurité des endpoints métiers et API (au-delà de la simple requête HTTP), vous pouvez aussi croiser avec « Sécurité des API : authentification, autorisations et logique métier »
Déployer sans casser la prod : ordre des règles, mode “log”, challenges et rollback
La majorité des incidents WAF ne viennent pas d’une attaque sophistiquée ; ils viennent d’un faux positif sur un chemin critique (paiement, login, callback PSP) qui a été “bloqué pour voir”. Oui, c’est du vécu. La méthode robuste : un déploiement en paliers : log → managed_challenge → block. Le “managed challenge” (quand disponible) a un avantage : Cloudflare adapte le challenge au client et au risque, ce qui limite l’expérience “captcha 2012”.
Petit repère (utile pour aligner sécurité et produit) :
| Action | Effet | Quand l’utiliser |
|---|---|---|
log |
aucun impact utilisateur, trace un événement | qualification, tuning, pré-prod |
managed_challenge |
challenge adaptatif | protection des endpoints sensibles sans tuer la conversion |
js_challenge / challenge |
plus intrusif selon client | quand vous assumez la friction (backoffice, zones à faible UX) |
block |
refus immédiat | signatures certaines, endpoints non légitimes, attaques évidentes |
skip |
bypass de certains produits | “kill switch” ciblé, exceptions (avec garde-fous) |
L’ordre compte. Dans Cloudflare, les règles sont évaluées selon leur phase et leur priorité. Une règle très large (“tout ce qui contient api dans l’URL”) placée trop haut va annuler vos exceptions plus bas. Stratégie :
- D’abord les allowlists explicites (healthchecks, PSP, webhooks signés, monitoring).
- Ensuite les règles ciblées sur routes sensibles.
- Enfin les règles génériques (pays, ASN, user-agent grossier), plutôt en challenge.
Un mini-scenario très réaliste (typiquement vu en période de promo / soldes / Black Friday) :
- le trafic augmente,
- vous activez une règle “anti-bot” sur
/checkout, - un partenaire (PSP / anti-fraude / module 3DS) change une partie de ses IP sortantes,
- résultat : chute de conversion et tickets “je ne peux plus payer”. D’où l’importance d’avoir une allowlist dédiée aux callbacks et une stratégie de rollback “chirurgicale”.
Et si vous avez besoin de filtrer des webhooks entrants, faites-le intelligemment : par IP (quand le fournisseur publie des ranges), par host, par chemin, et surtout par signature applicative (HMAC). Les règles WAF ne remplacent pas une validation X-HubSpot-Signature ou équivalent ; elles réduisent la surface. Pour un exemple concret côté webhooks, voir : Webhooks HubSpot et sécurité (HMAC)
Côté rollback, évitez le théâtre : “on désactive tout le WAF”. Préparez un kill switch contrôlé : une règle skip (ou une désactivation ciblée) sur un chemin précis, limitée à une fenêtre de temps, documentée. Et surtout, corrélez les impacts avec vos métriques produit (taux de conversion, erreurs 4xx/5xx, panier). Le WAF n’est pas une fin en soi : c’est un composant de fiabilité, comme la perf. Sur l’observation côté utilisateur, l’article RUM vs monitoring synthétique peut vous aider à instrumenter l’impact réel.
Checklist “déploiement safe” (simple mais efficace) :
- [ ] Règle bornée par
host+path(éviter les règles “globales”) - [ ] Démarrage en
logavec une fenêtre d’observation (ex. 24–72h) - [ ] Exclusions explicites pour PSP/webhooks/healthchecks
- [ ] Passage en
managed_challengeuniquement après analyse des événements - [ ] Passage en
blockréservé aux cas très sûrs, avec rollback prêt
Mesurer et investiguer : logs WAF, SIEM, métriques et corrélation (sinon vous pilotez à l’aveugle)
Une règle WAF personnalisée sans observabilité, c’est une opinion. Et on a déjà trop d’opinions dans la tech. Votre objectif : être capable de répondre vite à trois questions : qui a été bloqué, pourquoi, et avec quel impact. Dans Cloudflare, commencez par exploiter les Firewall Events et le mode log pour qualifier le trafic : distribution par chemin, pays, ASN, user-agent, score de menace, et surtout taux de faux positifs sur vos chemins critiques.
Quelques analyses qui donnent vite du signal (et évitent le “on bloque au hasard”) :
- Top chemins par action (
log/challenge/block) : identifiez si un endpoint “métier” est touché. - Top ASN : un pic sur des ASN cloud peut indiquer du bot; un pic sur des FAI grand public peut indiquer que vous bloquez des clients.
- Ratio challenge → succès sur
/login: un challenge qui explose peut signaler du credential stuffing… ou une régression de règle.
Pour aller plus loin, Logpush (selon plan) permet d’exporter les événements vers un stockage/outil d’analyse (SIEM, data lake, etc.). L’intérêt n’est pas de faire joli : c’est de corréler avec vos logs applicatifs (ex. request_id), vos traces, et vos métriques d’infra. Si vous êtes déjà dans une démarche observabilité moderne, vous pouvez vous appuyer sur OpenTelemetry pour unifier métriques/traces/logs : OpenTelemetry et observabilité
Point conformité (souvent sous-estimé) : les logs WAF peuvent contenir des données personnelles (IP, user-agent, parfois des paramètres si vous les journalisez). En France/UE, ça implique de traiter le sujet comme un flux de données : finalité, durée de conservation, accès, et transfert éventuel. Sans dramatiser, il faut au minimum éviter de pousser “n’importe quoi” dans un SIEM sans politique de rétention.
Ensuite, industrialisez les alertes. Exemple concret : alerter si une règle “challenge login” dépasse un certain volume (symptôme d’attaque credential stuffing) ou si une règle “allow webhook PSP” chute brutalement (symptôme d’un changement de range IP côté fournisseur, ou d’un blocage involontaire). Prometheus reste une option solide pour structurer l’alerting et les SLO/SLA, même si Cloudflare n’est pas nativement “Prometheus-first”. Pour la mise en place, voir : Prometheus quickstart
Enfin, pour investiguer vite, documentez à l’avance “où chercher” :
- dans Cloudflare : l’event WAF (règle, expression, action, champs de requête),
- dans l’app : l’ID de requête côté reverse proxy / app,
- côté produit : l’impact (erreurs, abandon, baisse de conversion). Sans cette corrélation, vous allez perdre du temps à débattre : “c’est Cloudflare” vs “c’est le backend”.
Automatiser et gouverner : API, Terraform, GitOps… et un minimum de discipline
Gérer des Cloudflare Custom Rules à la main dans le dashboard, c’est acceptable… jusqu’à ce que vous en ayez 30, trois environnements, et une équipe qui tourne. À ce stade, la bonne pratique est de passer en Infrastructure as Code : Terraform (provider Cloudflare) ou gestion via Cloudflare API. Les docs Terraform : docs Terraform (provider Cloudflare) ; l’API : API Cloudflare. Objectif : versionner, relire en PR, tracer qui a changé quoi, et déployer de façon reproductible.
Deux bénéfices concrets (au-delà du “c’est propre”) :
- Reproductibilité multi-environnements : staging/préprod/prod avec des différences contrôlées (ex. allowlists distinctes).
- Traçabilité : vous pouvez rattacher une modification WAF à un ticket, une MR/PR et un contexte (attaque en cours, tuning, correction d’un faux positif).
Techniquement, vous voulez aussi des tests. Oui, on peut tester des règles WAF. Pas “en unit test pur” comme une fonction Go, mais via :
- une batterie de requêtes de validation (curl/k6) sur staging,
- des golden samples (requêtes attendues/invalides),
- et une étape CI qui refuse les règles trop larges (ex. regex non bornées, conditions sans
host, etc.).
Une pratique simple et efficace : maintenir un petit jeu de requêtes “doit passer / doit être challengé / doit être bloqué” pour les chemins critiques. Exemple (au format checklist) :
- [ ]
GET /depuis France (FAI) : passe - [ ]
POST /loginavec signaux suspects : challenge - [ ]
POST /webhook/pspdepuis IP non allowlistée : bloqué - [ ]
GET /adminhors VPN : challenge ou bloc (selon politique)
Dans une approche DevSecOps, le WAF est un contrôle en bordure qui doit évoluer au même rythme que l’appli. Si vous structurez déjà la sécurité dans vos pipelines, l’article « DevSecOps-as-a-service : intégrer la sécurité au pipeline CI/CD » donne un cadre.
Enfin, gouvernance minimale (sinon c’est la fête du slip) : conventions de nommage (WAF-LOGIN-CHALLENGE-v3), tags (app, criticité, owner), date d’expiration pour les règles “temporaires”, et un runbook d’incident.
Astuce concrète : ajoutez une règle “temporaire” uniquement si elle a :
- un propriétaire explicite,
- une date d’expiration,
- et un lien vers l’événement qui l’a motivée (attaque, faux positif, changement de partenaire).
Si vous avez un doute sur une règle qui commence à bloquer des clients (ou pire, des callbacks de paiement), prévoyez une filière d’escalade. Les pages internes utiles existent : Urgence cybersécurité et Audit Cybersécurité.
Si vous voulez pousser le sujet “end-to-end” (de l’edge WAF jusqu’à l’infra), la brique DevOps compte aussi : DevOps, création et optimisation d’infrastructures d’hébergement. Parce que oui : un WAF parfait ne sauvera pas un backend qui tombe au premier pic, et un backend parfait n’aime pas les attaques par formulaires. Sur ce dernier point, voir aussi « Attaques par formulaires de contact : l’approche Zero Trust »