🛡️ Mini-Projet — Serveur Express Production-Ready
Serveur Express avec toute la stack de sécurité production : helmet, cors, rate-limit, dotenv, asyncHandler, error handler.
Aperçu des fonctionnalités
🪖
helmet
En-têtes HTTP sécurisés
🌐
cors
Origines autorisées
⏱️
rate-limit
100 req / 15 min
🔑
dotenv
Variables d'env
🔄
asyncHandler
Erreurs async auto
📋
morgan
Logs dev uniquement
.env.example
PORT=3011
NODE_ENV=development
JWT_SECRET=change_this_secret_in_production
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100
Copiez ce fichier en .env et adaptez les valeurs.
Ne commitez jamais .env dans git — ajoutez-le dans .gitignore.
server.js — Code complet
require('dotenv').config();
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const morgan = require('morgan');
// Valider les variables requises avant tout
const required = ['PORT', 'NODE_ENV'];
required.forEach(k => {
if (!process.env[k]) { console.error(`❌ Variable manquante: ${k}`); process.exit(1); }
});
const app = express();
const PORT = parseInt(process.env.PORT) || 3011;
const isDev = process.env.NODE_ENV !== 'production';
app.use(helmet());
app.use(cors({
origin: (process.env.ALLOWED_ORIGINS || 'http://localhost:3000').split(','),
credentials: true
}));
app.use(rateLimit({
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000,
max: parseInt(process.env.RATE_LIMIT_MAX) || 100,
message: { success: false, error: 'Trop de requêtes, réessayez plus tard.' }
}));
if (isDev) app.use(morgan('dev'));
app.use(express.json({ limit: '10kb' }));
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
app.get('/health', (req, res) => res.json({ status: 'ok', env: process.env.NODE_ENV }));
app.get('/secure-data', asyncHandler(async (req, res) => {
await new Promise(r => setTimeout(r, 50));
res.json({ success: true, data: { message: 'Données sécurisées' } });
}));
app.use((req, res) => res.status(404).json({ success: false, error: 'Route introuvable' }));
app.use((err, req, res, next) => {
if (isDev) console.error(err.stack);
res.status(err.status || 500).json({
success: false,
error: isDev ? err.message : 'Erreur serveur interne'
});
});
app.listen(PORT, () => console.log(`🟢 http://localhost:${PORT} [${process.env.NODE_ENV}]`));
Checklist Sécurité Production
- ✓helmet()Configure automatiquement les en-têtes HTTP de sécurité
- ✓cors() avec whitelistSeules les origines explicitement autorisées peuvent appeler l'API
- ✓Rate limiting100 requêtes max par IP sur 15 minutes — protection DDoS de base
- ✓dotenv + validationVariables chargées depuis .env, process.exit(1) si manquantes
- ✓asyncHandlerToutes les erreurs async propagées automatiquement via next(err)
- ✓Error handler 4-paramsStack trace masqué en production, status 500 par défaut
- ✓express.json({ limit: '10kb' })Limite la taille des requêtes pour éviter les attaques payload
- ✓morgan conditionnelLogs uniquement en développement, pas de verbosité en production
Démarrage
# Installer les dépendances
npm install
# Copier la config (puis éditer les valeurs)
cp .env.example .env
# Lancer en développement
node server.js
# → 🟢 http://localhost:3011 [development]
# Tester les routes
curl http://localhost:3011/health
curl http://localhost:3011/secure-data
curl http://localhost:3011/route-inexistante # → 404