Sécuriser son application web : le guide OWASP 2025
La cybersécurité n'est plus optionnelle pour les PME belges. **73% d'entre elles ont subi au moins une tentative de cyberattaque en 2024**. Ce guide décrypte les 10 vulnérabilités critiques identifiées par l'OWASP et vous montre comment protéger efficacement votre application web.
Comprendre l'OWASP Top 10
L'**OWASP (Open Web Application Security Project)** est une organisation à but non lucratif qui publie tous les 3-4 ans une liste des vulnérabilités web les plus critiques. Ces 10 failles représentent **80% des incidents de sécurité** recensés dans les applications web.
Pourquoi c'est crucial pour votre entreprise
- **Conformité RGPD** : Une faille exposant des données personnelles peut coûter jusqu'à 4% de votre chiffre d'affaires
- **Réputation** : 60% des clients perdent confiance après une fuite de données
- **Coût financier** : Le coût moyen d'une cyberattaque pour une PME belge s'élève à **85 000€**
Injection SQL, NoSQL et Command
L'injection permet à un attaquant d'exécuter du code malveillant dans votre base de données ou votre système.
Exemple de code vulnérable
// ❌ DANGEREUX - Injection SQL possible
const email = req.body.email;
const query = `SELECT * FROM users WHERE email = '${email}'`;
db.query(query);
Un attaquant peut injecter : `admin@site.com' OR '1'='1` et accéder à tous les comptes.
Solution : Requêtes préparées
// ✅ SÉCURISÉ - Paramètres échappés automatiquement
const email = req.body.email;
const query = 'SELECT * FROM users WHERE email = $1';
const result = await db.query(query, [email]);
Avec un ORM moderne (Prisma)
// ✅ SÉCURISÉ - Protection intégrée
const user = await prisma.user.findUnique({
where: { email: email } // Échappement automatique
});
Authentification cassée
Des mécanismes d'authentification faibles ouvrent la porte aux attaques : sessions non expirées, mots de passe faibles, absence de 2FA.
1. Implémenter NextAuth.js
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import CredentialsProvider from 'next-auth/providers/credentials';
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
CredentialsProvider({
async authorize(credentials) {
// Vérification sécurisée
const user = await verifyUser(credentials);
return user || null;
}
})
],
session: {
strategy: 'jwt',
maxAge: 24 * 60 * 60, // 24 heures
},
pages: {
signIn: '/login',
error: '/auth/error',
},
};
export default NextAuth(authOptions);
2. Hash sécurisé avec bcrypt
import bcrypt from 'bcryptjs';
// Enregistrement d'un utilisateur
async function registerUser(email: string, password: string) {
const saltRounds = 12; // Coût computationnel élevé
const hashedPassword = await bcrypt.hash(password, saltRounds);
await db.user.create({
data: { email, password: hashedPassword }
});
}
// Vérification lors du login
async function verifyUser(email: string, password: string) {
const user = await db.user.findUnique({ where: { email } });
if (!user) return null;
const isValid = await bcrypt.compare(password, user.password);
return isValid ? user : null;
}
3. Rate limiting sur les endpoints sensibles
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, '15 m'), // 5 tentatives / 15 min
});
export async function POST(request: Request) {
const ip = request.headers.get('x-forwarded-for') ?? 'unknown';
const { success } = await ratelimit.limit(ip);
if (!success) {
return Response.json(
{ error: 'Trop de tentatives, réessayez dans 15 minutes' },
{ status: 429 }
);
}
// Traitement de la requête...
}
Exposition de données sensibles
Les données sensibles doivent être chiffrées en transit (HTTPS) et au repos.
Configuration HTTPS stricte
// next.config.ts
export default {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-Frame-Options',
value: 'DENY'
},
{
key: 'X-XSS-Protection',
value: '1; mode=block'
}
],
},
];
},
};
Gestion sécurisée des secrets
# .env.local - JAMAIS commité dans Git
DATABASE_URL="postgresql://user:password@localhost:5432/db"
JWT_SECRET="votre-secret-aleatoire-de-32-caracteres-minimum"
STRIPE_SECRET_KEY="sk_live_..."
Validation des variables d'environnement
// lib/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});
export const env = envSchema.parse(process.env);
Cross-Site Scripting (XSS)
Le XSS permet d'injecter du JavaScript malveillant dans vos pages web.
Protection native de React
// ✅ SÉCURISÉ - React échappe automatiquement
function UserProfile({ username }) {
return <h1>Bienvenue {username}</h1>;
}
Attention au HTML brut
// ❌ DANGEREUX
function RichContent({ html }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
// ✅ SÉCURISÉ - Nettoyage préalable
import DOMPurify from 'isomorphic-dompurify';
function RichContent({ html }) {
const cleanHTML = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href']
});
return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
}
Cross-Site Request Forgery (CSRF)
Le CSRF force un utilisateur authentifié à exécuter des actions non désirées.
Protection avec middleware Next.js
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Vérifier l'origine des requêtes
const origin = request.headers.get('origin');
const host = request.headers.get('host');
if (request.method !== 'GET') {
if (!origin || !origin.includes(host!)) {
return new NextResponse('Forbidden', { status: 403 });
}
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};
Checklist de sécurité par niveau
Niveau 1 : Essentiel (obligatoire)
- ✓ HTTPS activé avec HSTS
- ✓ Mots de passe hashés (bcrypt avec salt >= 12)
- ✓ Requêtes SQL préparées ou ORM
- ✓ Variables d'environnement sécurisées (.env.local)
- ✓ Headers de sécurité configurés
- ✓ Dépendances à jour (npm audit)
Niveau 2 : Recommandé
- ✓ Authentification à deux facteurs (2FA)
- ✓ Rate limiting sur toutes les API
- ✓ Logs d'audit avec rotation
- ✓ Monitoring d'erreurs (Sentry, LogRocket)
- ✓ Backups quotidiens automatiques et chiffrés
- ✓ CSP (Content Security Policy) strict
Niveau 3 : Avancé
- ✓ Tests SAST/DAST en CI/CD
- ✓ Audit automatique des dépendances (Dependabot)
- ✓ WAF (Web Application Firewall)
- ✓ Pentest annuel par un tiers de confiance
- ✓ Plan de réponse aux incidents documenté et testé
Outils recommandés
**SAST (Static Application Security Testing)**
- Snyk - Scan de dépendances vulnérables
- SonarQube - Analyse de code statique
**DAST (Dynamic Application Security Testing)**
- OWASP ZAP - Scanner de vulnérabilités web
- Burp Suite - Tests de pénétration avancés
**Monitoring & Alerting**
- Sentry - Tracking d'erreurs en temps réel
- LogRocket - Session replay pour détecter les abus
**Validation**
- SecurityHeaders.com - Vérifier vos headers HTTP
- SSL Labs - Tester votre configuration HTTPS
**Besoin d'un audit de sécurité ?** Smidjan propose des audits OWASP complets pour identifier et corriger les failles de votre application web.
Besoin d'accompagnement ?
Smidjan vous aide à mettre en place ces solutions pour votre entreprise en Belgique.
Discutons de votre projet →