Ce que tu apprends
- Rate-limiter chaque endpoint public pour stopper le brute force, le spam et l'abus qui gonfle la facture
- Les headers CSP, chiffrer les credentials stockées et tenir un audit log
- Une checklist pré-public de repo pour que les secrets de l'historique ne deviennent jamais publics
Vue d'ensemble
À l'instant où votre app est sur l'Internet public, elle est sondée par des bots en quelques minutes. Vous n'avez pas besoin d'une équipe de sécurité pour être sûr contre les attaques courantes, vous avez besoin d'une poignée d'essentiels, appliqués systématiquement : plafonnez chaque endpoint public avec un rate limit, verrouillez avec une CSP ce que le navigateur exécutera, chiffrez les credentials que vous stockez, loggez qui a fait quoi, et ne passez jamais un repo en public sans auditer son historique pour les secrets. Cette leçon rend chacun concret.
Ce que vous allez apprendre
Vous allez apprendre à ajouter des rate limits aux endpoints publics, à poser un header Content Security Policy, à chiffrer les credentials stockées au repos, à tenir un audit log utile et à faire tourner un audit pré-public de repo qui attrape les secrets cachés dans de vieux commits. Ce sont les mesures qui séparent un projet de hobby de quelque chose sur lequel vous pouvez responsablement diriger de vrais utilisateurs.
Prérequis
Les leçons sur les secrets des Cours 1 et 3, car plusieurs mesures ici s'appuient sur le fait de garder les secrets dans les variables d'environnement et hors du code. Une app déployée avec au moins un endpoint ou formulaire public rend la leçon concrète, mais vous pouvez tout appliquer à votre prochain projet dès le premier commit.
Le problème
Trois omissions nuisent aux petits builders encore et encore. Premièrement : un endpoint non protégé se fait marteler - un formulaire de login brute-forcé, un formulaire de contact spammé ou un endpoint d'IA appelé en boucle jusqu'à ce que votre facture fournisseur explose. Deuxièmement : une clé API ou un mot de passe stocké siège en clair, si bien qu'une seule fuite de base de données donne à un attaquant tout d'un coup. Troisièmement, et le plus fréquent : une fondatrice rend un repo public pour le partager, et un secret committé il y a deux ans est maintenant pour toujours sur l'internet ouvert. Chacun est évitable avec une habitude.
Rate-limitez chaque endpoint public
Un rate limit plafonne combien de fois un seul client peut toucher un endpoint dans une fenêtre de temps. C'est le contrôle de sécurité le moins cher et à plus haut levier que vous avez, et chaque endpoint qu'un inconnu peut atteindre en a besoin d'un : login, signup, réinitialisation de mot de passe, formulaires de contact et surtout tout endpoint qui vous coûte de l'argent par appel, comme un qui déclenche un LLM. Limitez par IP pour le trafic anonyme et par utilisateur ou clé API pour le trafic authentifié. Quand la limite est dépassée, renvoyez un 429 et arrêtez-vous.
// Un limiteur à fenêtre fixe minimal. En production, utilisez un store partagé
// (Redis, Upstash ou votre BD) pour qu'il fonctionne sur plusieurs serveurs.
const hits = new Map<string, { count: number; resetAt: number }>()
export function rateLimit(key: string, max = 10, windowMs = 60_000) {
const now = Date.now()
const entry = hits.get(key)
if (!entry || now > entry.resetAt) {
hits.set(key, { count: 1, resetAt: now + windowMs })
return { ok: true }
}
if (entry.count >= max) return { ok: false, retryAfter: entry.resetAt - now }
entry.count += 1
return { ok: true }
}
// Dans votre handler :
// const limit = rateLimit(`login:${ip}`, 5, 60_000)
// if (!limit.ok) return new Response('Too many requests', { status: 429 })Headers CSP et chiffrer les credentials stockées
Une Content Security Policy dit au navigateur exactement quelles sources il a le droit de charger pour les scripts, styles et images. C'est votre plus forte défense contre le cross-site scripting : même si un attaquant injecte une balise script, le navigateur refuse de l'exécuter parce que la source n'est pas sur votre allowlist. Démarrez strict et n'assouplissez que ce que vous devez. Séparément, tout ce que vous stockez de sensible - une clé API tierce, un token OAuth, un secret utilisateur - doit être chiffré au repos, pour qu'une intrusion en base de données livre du texte chiffré, pas des credentials fonctionnelles. La clé de chiffrement elle-même vit dans une variable d'environnement, jamais dans la base de données qu'elle protège.
Content-Security-Policy: default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.your-provider.com;
frame-ancestors 'none';
base-uri 'self'- default-src 'self' veut dire : sauf indication contraire, ne charger que depuis votre propre domaine.
- connect-src contrôle quelles API le navigateur a le droit d'appeler - ne listez que vos vrais backends.
- frame-ancestors 'none' empêche d'autres sites d'embarquer la vôtre dans un iframe (clickjacking).
- Chiffrez les secrets stockés avec une librairie, pas à la main ; gardez la clé dans une env var, faites-la tourner si elle fuite un jour.
Audit logs : savoir qui a fait quoi
Quand quelque chose tourne mal - un remboursement émis, un compte supprimé, un plan rétrogradé - vous devez répondre « qui a fait ça, quand et d'où ». Un audit log est un enregistrement en append-only des actions sensibles : l'acteur, l'action, la cible, un timestamp et l'IP source. Ce n'est pas la même chose que vos logs applicatifs ; c'est une trace délibérée pour la sécurité et la responsabilité. Loggez chaque action qui déplace de l'argent, change des permissions ou touche les données d'un autre utilisateur. Ne loggez jamais les secrets eux-mêmes, seulement que l'action a eu lieu.
La checklist pré-public de repo
C'est celle qui mord le plus fort. Supprimer une clé de votre commit le plus récent ne la retire pas de l'historique - elle siège toujours dans un vieux commit que tout le monde peut lire dès que le repo passe en public. Avant de passer un repo de privé à public, parcourez cette checklist à chaque fois. Si vous trouvez un secret dans l'historique, le seul coup sûr est de traiter ce secret comme compromis : faites-le tourner immédiatement, puis nettoyez l'historique.
- Scannez l'historique complet pour les secrets, pas seulement les fichiers actuels. Utilisez un outil comme gitleaks ou trufflehog : gitleaks detect --source . attrape clés, tokens et mots de passe sur chaque commit.
- Confirmez que .env et chaque fichier de secret sont dans .gitignore et n'ont jamais été committés.
- Vérifiez les clés en dur, les URL internes, les données clients et les credentials dans le code et les commentaires.
- Si un secret a jamais été committé : faites-le tourner d'abord (supposez-le déjà public), puis réécrivez l'historique pour le retirer avant de passer en public.
- Ce n'est qu'après un scan propre que vous passez le repo en public.
# Auditer tout l'historique Git pour les secrets fuités avant de passer en public
gitleaks detect --source . --verbose
# Si quelque chose est trouvé, FAITES TOURNER le secret d'abord, puis nettoyez l'historique.Erreurs fréquentes
Les récurrentes : livrer un endpoint d'IA ou d'e-mail sans rate limit et se réveiller devant une facture à cinq chiffres ; stocker les tokens tiers en clair, si bien qu'une fuite compromet chaque compte connecté ; sauter la CSP parce qu'elle est fastidieuse et ensuite avaler un XSS ; et le classique - passer un repo en public pour « partager le projet » sans auditer l'historique, et fuiter une clé qui traîne là depuis des mois. Chacune est évitée par une habitude de cette leçon.
ROI business
La sécurité est invisible quand elle marche et catastrophique quand elle ne marche pas. Une clé fuitée peut vider un budget du jour au lendemain, une intrusion dans les credentials stockées peut mettre fin à une entreprise, et une seule fuite de repo public a coûté aux fondateurs de l'argent réel et de vrais clients. Les essentiels ici vous coûtent un après-midi à mettre en place puis tournent pour toujours. Pour une équipe pilotée par agent, cela compte double : les agents génèrent des endpoints vite, donc la discipline « chaque endpoint public reçoit un rate limit, chaque secret est chiffré, chaque repo est audité » doit être une règle que l'agent suit, pas quelque chose dont vous vous souvenez.
Checklist
Confirmez chacun de ces points avant de diriger de vrais utilisateurs sur quoi que ce soit que vous avez bâti.
- Chaque endpoint public et coûteux a un rate limit qui renvoie 429 en cas de dépassement.
- Un header Content Security Policy est posé et aussi strict que votre app le permet.
- Les credentials et tokens stockés sont chiffrés au repos, la clé dans une env var.
- Vous avez fait tourner un scan de secrets sur tout l'historique avant chaque repo public et fait tourner tout ce qui a été trouvé.
Ressources
Gardez gitleaks ou trufflehog installé et ajoutez le scan d'historique à votre rituel pré-public. Le OWASP Top 10 et la référence CSP de MDN sont les sources intemporelles quand vous avez besoin de profondeur. Mettez « rate-limite cet endpoint » et « chiffre ce secret stocké » dans vos règles de projet, pour que les agents les appliquent sans qu'on le demande.
Votre mission
Ajoutez un rate limit à un vrai endpoint et confirmez qu'il renvoie 429 quand vous le dépassez. Posez un header CSP sur votre app et corrigez ce qu'il casse, jusqu'à ce que la page fonctionne sous une policy stricte. Puis faites tourner gitleaks contre un de vos repos et lisez l'output - même un résultat propre vous apprend à faire confiance à la vérification avant de passer un jour en public.
Prochaine leçon
Sûr et durci, la prochaine leçon traite le droit et la conformité : RGPD, consentement cookies conforme y compris Global Privacy Control, et les lois de protection des données américaines et suisses, expliquées sans maux de tête.

Commentaires
Chargement des commentaires.
Poster un commentaire