Formulaire de Contact Sécurisé
Ce fichier détaille les meilleures pratiques de sécurité appliquées dans l'implémentation d'un formulaire de contact sécurisé , étape par étape, pour une application Next.js…
Ce fichier détaille les meilleures pratiques de sécurité appliquées dans l'implémentation d'un formulaire de contact sécurisé, étape par étape, pour une application Next.js avec une API Node.js/Next.js.
Auteur : Anas Education (opens in a new tab)
Dernière mise à jour : 24/05/2025
Objectif#
Garantir que les données envoyées via le formulaire de contact :
- Ne contiennent aucune injection XSS ou HTML
- Ne soient pas utilisées pour des attaques par injection d'en-têtes d'e-mail
- Respectent un format strictement validé
- Ne soient pas exploitables pour un spam ou DoS
- Soient transmises de manière sécurisée et auditée
Étapes de Sécurisation#
Étape 1 · Sanitation des Entrées Utilisateur#
ts
function sanitizeInput(input: string): string {
return input
.replace(/<[^>]*>?/gm, "") // supprimer les balises HTML
.replace(/javascript:/gi, "") // éliminer javascript:
.replace(/on\w+\s*=/gi, "") // supprimer onclick, onerror...
.replace(/["']/g, "") // retirer les guillemets
.replace(/[\r\n]/g, " ") // éviter les injections d'en-tête
.replace(/[<>]/g, "") // supprimer < et >
.trim()
}Étape 2 · Validation de la Structure#
ts
function validateEmail(email: string): boolean { ... }
function validateName(name: string): boolean { ... }
function validateSubject(subject: string): boolean { ... }
function validateMessage(message: string): boolean { ... }Étape 3 · Limitation de la portée des subjects#
ts
const allowedServices = ["Secure Development Service", "Pentest Service"]
const cleanService = sanitizedSubject.replace("Request: ", "")
if (!allowedServices.includes(cleanService)) {
return NextResponse.json({ error: "Invalid subject content" }, { status: 400 })
}Étape 4 · Protection contre les Injections d'en-têtes#
ts
const bannedPatterns = [/bcc:/i, /cc:/i, /content-type:/i, /to:/i, /from:/i, /reply-to:/i]
for (const pattern of bannedPatterns) {
if (pattern.test(sanitizedMessage) || pattern.test(sanitizedSubject)) {
return NextResponse.json({ error: "Oops...Error !!" }, { status: 400 })
}
}Étape 5 · Encodage HTML (contre XSS dans les e-mails)#
ts
function escapeHTML(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
}Étape 6 · Rate Limiting côté serveur#
ts
function checkRateLimit(ip: string): boolean {
// max 5 requêtes / 15 minutes
}Étape 7 · Honeypot (Anti-Bot invisible)#
Frontend:
html
<input type="text" name="website" style="display:none" />Backend:
ts
if ("website" in body && body.website !== "") {
return NextResponse.json({ error: "Bot detected" }, { status: 403 })
}Étape 8 · Envoi des E-mails via Nodemailer#
- SMTP sécurisé avec
Gmail - Fallback en cas d'erreur (
try/catch) replyToau lieu defrom(moins risqué)
Conseils Bonus#
.env.localest privé (.gitignore)- CSRF Token conseillé si utilisateur connecté
- Logging : Pino / Winston
- Tests unitaires + fuzzing = BOOOM!!
Résultat#
Un formulaire :
- Résilient contre XSS / Header Injection / Spam Bot
- Nettoyé / Validé / Loggé
- Pro niveau pour montrer en portfolio par exemple