🛡️ 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 whitelist
    Seules les origines explicitement autorisées peuvent appeler l'API
  • Rate limiting
    100 requêtes max par IP sur 15 minutes — protection DDoS de base
  • dotenv + validation
    Variables chargées depuis .env, process.exit(1) si manquantes
  • asyncHandler
    Toutes les erreurs async propagées automatiquement via next(err)
  • Error handler 4-params
    Stack 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 conditionnel
    Logs 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
← Cours N11 Exercices N11 →