Retour au blog

Sécurité Web en 2025 : OWASP Top 10 et Comment Protéger Vos Applications JavaScript

Salut HaWkers, avec les cyberattaques augmentant exponentiellement, la sécurité n'est plus la responsabilité des seuls spécialistes. Tout développeur doit connaître l'OWASP Top 10 et implémenter les protections de base.

Explorons les vulnérabilités les plus communes et comment protéger vos applications JavaScript.

OWASP Top 10 : Les Vulnérabilités Critiques

const owaspTop10_2025 = {
  1: 'Broken Access Control',
  2: 'Cryptographic Failures',
  3: 'Injection (SQL, XSS, etc)',
  4: 'Insecure Design',
  5: 'Security Misconfiguration',
  6: 'Vulnerable Components',
  7: 'Authentication Failures',
  8: 'Software and Data Integrity',
  9: 'Security Logging Failures',
  10: 'Server-Side Request Forgery (SSRF)'
};

1. Prévenir le XSS (Cross-Site Scripting)

// ❌ VULNÉRABLE - Ne jamais faire ça !
function renderUserInput(input) {
  document.getElementById('output').innerHTML = input;
  // Si input = "<script>alert('XSS')</script>"
  // Le script s'exécute !
}

// ✅ SÉCURISÉ - Sanitize input
import DOMPurify from 'dompurify';

function renderUserInputSafe(input) {
  const clean = DOMPurify.sanitize(input);
  document.getElementById('output').innerHTML = clean;
}

// ✅ ENCORE PLUS SÉCURISÉ - Utilisez textContent
function renderText(input) {
  document.getElementById('output').textContent = input;
  // Le HTML n'est pas interprété
}

// React échappe automatiquement
function UserProfile({ username }) {
  return <div>{username}</div>; // Safe !
}

2. Prévention de l'Injection SQL

// ❌ VULNÉRABLE - Concaténation de string
async function getUser(userId) {
  const query = `SELECT * FROM users WHERE id = ${userId}`;
  // Si userId = "1 OR 1=1", retourne TOUS les utilisateurs !
  return await db.query(query);
}

// ✅ SÉCURISÉ - Prepared statements
async function getUserSafe(userId) {
  const query = 'SELECT * FROM users WHERE id = ?';
  return await db.query(query, [userId]);
}

// ✅ ORM encore plus sécurisé
async function getUserORM(userId) {
  return await User.findById(userId);
  // L'ORM sanitize automatiquement
}

3. Authentification Sécurisée

import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

class AuthService {
  // Enregistrer un utilisateur
  async register(email, password) {
    // Valider la force du mot de passe
    if (password.length < 12) {
      throw new Error('Le mot de passe doit avoir minimum 12 caractères');
    }

    // Hash avec bcrypt (JAMAIS sauvegarder le mot de passe en clair !)
    const saltRounds = 12;
    const hashedPassword = await bcrypt.hash(password, saltRounds);

    await db.users.create({
      email,
      password: hashedPassword
    });
  }

  // Login
  async login(email, password) {
    const user = await db.users.findOne({ email });

    if (!user) {
      // ✅ Message générique (ne révèle pas si l'email existe)
      throw new Error('Identifiants invalides');
    }

    // Vérifier le mot de passe
    const isValid = await bcrypt.compare(password, user.password);

    if (!isValid) {
      throw new Error('Identifiants invalides');
    }

    // JWT avec expiration courte
    const token = jwt.sign(
      { userId: user.id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: '1h' }
    );

    return { token, user: { id: user.id, email: user.email } };
  }

  // Vérifier le token
  verifyToken(token) {
    try {
      return jwt.verify(token, process.env.JWT_SECRET);
    } catch {
      throw new Error('Token invalide');
    }
  }
}

4. Protection CSRF

// Backend - Express
import csrf from 'csurf';

const csrfProtection = csrf({ cookie: true });

app.post('/api/transfer', csrfProtection, async (req, res) => {
  // Token CSRF validé automatiquement
  await processTransfer(req.body);
  res.json({ success: true });
});

// Frontend - Envoyer le token
async function transferMoney(amount, to) {
  const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

  await fetch('/api/transfer', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify({ amount, to })
  });
}

5. Validation d'Input

import { z } from 'zod';

// Schéma de validation
const userSchema = z.object({
  email: z.string().email(),
  age: z.number().min(18).max(120),
  username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/)
});

// Valider l'input
async function createUser(data) {
  try {
    // Valide et parse
    const validated = userSchema.parse(data);

    // ✅ Données garanties valides
    return await db.users.create(validated);
  } catch (error) {
    throw new Error('Données invalides');
  }
}

6. Rate Limiting

import rateLimit from 'express-rate-limit';

// Prévenir le brute force
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 tentatives
  message: 'Trop de tentatives de connexion. Réessayez dans 15 minutes.'
});

app.post('/api/login', loginLimiter, async (req, res) => {
  // Logique de login
});

// Rate limit général
const apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100 // 100 requêtes
});

app.use('/api/', apiLimiter);

7. Secure Headers

import helmet from 'helmet';

// Express - Helmet configure les headers sécurisés
app.use(helmet());

// Headers importants :
const securityHeaders = {
  'Content-Security-Policy': "default-src 'self'",
  'X-Frame-Options': 'DENY',
  'X-Content-Type-Options': 'nosniff',
  'Strict-Transport-Security': 'max-age=31536000',
  'X-XSS-Protection': '1; mode=block'
};

Checklist de Sécurité

const securityChecklist = [
  '✅ Valider TOUT input utilisateur',
  '✅ Utiliser prepared statements (SQL)',
  '✅ Sanitizer l\'output HTML',
  '✅ Implémenter le rate limiting',
  '✅ HTTPS en production (toujours !)',
  '✅ Passwords hashés avec bcrypt',
  '✅ JWT avec expiration courte',
  '✅ CSRF tokens dans les formulaires',
  '✅ Security headers (Helmet)',
  '✅ Dépendances à jour',
  '✅ Secrets en variables d\'environnement',
  '✅ Logging des événements de sécurité',
  '✅ CORS configuré correctement'
];

La sécurité n'est pas optionnelle en 2025. Avec des attaques de plus en plus sophistiquées, tout développeur est responsable du code sécurisé.

C'est parti !

🎯 Les Développeurs Sécurisés Ont Plus de Valeur

La connaissance en sécurité différencie les développeurs juniors des professionnels complets. Investissez dans une connaissance solide.

Commencez maintenant :

  • 9,90€ (paiement unique)

🚀 Accéder au Guide Complet

Commentaires (0)

Cet article n'a pas encore de commentaires. Soyez le premier!

Ajouter des commentaires