Qu'est-ce que le Top 10 des applications Web de l'OWASP ?

Le Top 10 de l'OWASP est le document de sensibilisation à la sécurité des applications web le plus largement reconnu. L'édition 2025 reflète le paysage des menaces le plus récent, en introduisant de nouvelles catégories telles que les défaillances de la chaîne d'approvisionnement des logiciels et la mauvaise gestion des conditions exceptionnelles.

1️⃣ A01 - Contrôle d'accès défaillant

Critical

Vue d'ensemble

Le contrôle d'accès permet d'appliquer la politique de manière à ce que les utilisateurs ne puissent pas agir en dehors des autorisations qui leur ont été accordées. Les défaillances conduisent généralement à la divulgation d'informations non autorisées, à la modification ou à la destruction de données, ou à l'exécution d'une fonction commerciale en dehors des limites de l'utilisateur.

Risque

Les attaquants peuvent exploiter les failles du contrôle d'accès pour accéder aux comptes d'autres utilisateurs, consulter des fichiers sensibles, modifier les données d'autres utilisateurs ou changer les droits d'accès.

Exemple de code vulnérable

Python ❌ Bad
# User ID taken directly from request without authorization check
@app.route('/api/user/<user_id>/profile')
def get_profile(user_id):
    user = db.get_user(user_id)  # No ownership check!
    return jsonify(user.to_dict())

Exemple de code sécurisé

Python ✅ Good
@app.route('/api/user/<user_id>/profile')
@login_required
def get_profile(user_id):
    # Verify the requesting user owns this resource
    if current_user.id != user_id and not current_user.is_admin:
        abort(403)

    user = db.get_user(user_id)
    if not user:
        abort(404)
    return jsonify(user.to_dict())

Liste de contrôle des mesures d'atténuation

2️⃣ A02 - Mauvaise configuration de la sécurité

High

Vue d'ensemble

Il y a mauvaise configuration de la sécurité lorsque les paramètres de sécurité sont définis, mis en œuvre ou maintenus de manière incorrecte. Il s'agit notamment de l'absence de renforcement de la sécurité, de l'activation de fonctions inutiles, de comptes par défaut avec des mots de passe inchangés, de messages d'erreur trop verbeux et d'en-têtes de sécurité HTTP mal configurés.

Risque

Des serveurs, des frameworks ou des services en nuage mal configurés peuvent exposer des données sensibles, permettre un accès non autorisé ou fournir aux attaquants des informations leur permettant de planifier d'autres attaques.

Exemple de code vulnérable

Python ❌ Bad
# Debug mode enabled in production, verbose errors exposed
app = Flask(__name__)
app.config['DEBUG'] = True  # Exposes stack traces!
app.config['SECRET_KEY'] = 'default-secret'  # Default key!

Exemple de code sécurisé

Python ✅ Good
import os

app = Flask(__name__)
app.config['DEBUG'] = False
app.config['SECRET_KEY'] = os.environ['SECRET_KEY']

@app.after_request
def set_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    response.headers['Content-Security-Policy'] = "default-src 'self'"
    return response

Liste de contrôle des mesures d'atténuation

3️⃣ A03 - Défaillances de la chaîne d'approvisionnement en logiciels

High

Vue d'ensemble

Nouveauté 2025. Se concentre sur les risques liés aux composants tiers, aux dépendances et aux pipelines CI/CD. Les attaquants ciblent la chaîne d'approvisionnement des logiciels en compromettant les paquets, en injectant du code malveillant dans les bibliothèques open-source ou en exploitant les vulnérabilités des pipelines de construction.

Risque

Une seule dépendance compromise peut affecter des milliers d'applications. Les attaques de la chaîne d'approvisionnement peuvent conduire au vol de données, à l'installation d'une porte dérobée ou à la compromission complète du système avec une détection minimale.

Exemple de code vulnérable

JavaScript ❌ Bad
// package.json with unpinned dependencies
{
  "dependencies": {
    "express": "*",           // Any version!
    "lodash": "^4.0.0",       // Wide range
    "unknown-pkg": "^1.0.0"   // Unvetted package
  }
}

Exemple de code sécurisé

JavaScript ✅ Good
// package.json with pinned versions + lockfile + audit
{
  "dependencies": {
    "express": "4.21.2",
    "lodash": "4.17.21"
  },
  "scripts": {
    "preinstall": "npx npm-audit-resolver",
    "integrity-check": "npm audit signatures"
  }
}
// Also: use package-lock.json, enable Dependabot/Renovate,
// generate SBOM, verify package provenance

Liste de contrôle des mesures d'atténuation

4️⃣ A04 - Défaillances cryptographiques

High

Vue d'ensemble

Défaillances liées à la cryptographie qui conduisent souvent à l'exposition de données sensibles. Il s'agit notamment de l'utilisation d'algorithmes obsolètes, de la génération de clés faibles, de l'absence de chiffrement des données en transit ou au repos, et de la validation incorrecte des certificats.

Risque

Un chiffrement faible ou manquant peut exposer des mots de passe, des numéros de carte de crédit, des dossiers médicaux, des informations personnelles et des secrets d'affaires, ce qui peut entraîner des violations de la réglementation (GDPR, PCI DSS).

Exemple de code vulnérable

Python ❌ Bad
import hashlib

# Storing passwords with weak hashing
def store_password(password: str) -> str:
    return hashlib.md5(password.encode()).hexdigest()  # MD5 is broken!

Exemple de code sécurisé

Python ✅ Good
import bcrypt

def store_password(password: str) -> bytes:
    # Use bcrypt with automatic salting
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt)

def verify_password(password: str, hashed: bytes) -> bool:
    return bcrypt.checkpw(password.encode(), hashed)

Liste de contrôle des mesures d'atténuation

5️⃣ A05 - Injection

Critical

Vue d'ensemble

Les failles d'injection se produisent lorsque des données non fiables sont envoyées à un interpréteur dans le cadre d'une commande ou d'une requête. L'injection SQL, l'injection NoSQL, l'injection de commandes OS et le Cross-Site Scripting (XSS) sont les formes les plus courantes. Des données hostiles peuvent inciter l'interprète à exécuter des commandes non souhaitées.

Risque

L'injection peut entraîner la perte ou la corruption de données, un accès non autorisé, une prise de contrôle complète de l'hôte ou un déni de service. L'injection SQL reste à elle seule l'un des vecteurs d'attaque les plus dangereux et les plus répandus.

Exemple de code vulnérable

Python ❌ Bad
# SQL injection via string concatenation
def get_user(username: str):
    query = f"SELECT * FROM users WHERE name = '{username}'"
    return db.execute(query)  # username = "' OR '1'='1"

Exemple de code sécurisé

Python ✅ Good
# Parameterized queries prevent SQL injection
def get_user(username: str):
    query = "SELECT * FROM users WHERE name = %s"
    return db.execute(query, (username,))

# For XSS prevention, escape output
from markupsafe import escape

def render_comment(comment: str) -> str:
    return f"<p>{escape(comment)}</p>"

Liste de contrôle des mesures d'atténuation

6️⃣ A06 - Conception non sécurisée

High

Vue d'ensemble

La conception non sécurisée fait référence aux risques liés aux défauts de conception et d'architecture. Elle nécessite l'utilisation de la modélisation des menaces, de modèles de conception sécurisés et d'architectures de référence. Une conception non sécurisée ne peut être corrigée par une mise en œuvre parfaite ; les contrôles de sécurité nécessaires n'ont jamais été créés pour se défendre contre des attaques spécifiques.

Risque

Les défauts de conception peuvent entraîner des vulnérabilités au niveau de la logique d'entreprise qui sont difficiles à détecter à l'aide d'outils automatisés. L'absence de limites de taux pour les opérations sensibles, l'absence d'authentification multifactorielle pour les actions critiques ou la détection insuffisante des fraudes sont autant de défaillances au niveau de la conception.

Exemple de code vulnérable

Python ❌ Bad
# Password reset with no rate limit or verification
@app.route('/reset-password', methods=['POST'])
def reset_password():
    email = request.form['email']
    new_pass = request.form['new_password']
    user = db.find_by_email(email)
    user.password = hash_password(new_pass)  # No token verification!
    db.save(user)

Exemple de code sécurisé

Python ✅ Good
from datetime import datetime, timedelta

@app.route('/reset-password', methods=['POST'])
@rate_limit("3/hour")
def reset_password():
    token = request.form['token']
    new_pass = request.form['new_password']

    # Verify time-limited, single-use token
    reset_req = db.find_reset_token(token)
    if not reset_req or reset_req.used or reset_req.expires < datetime.utcnow():
        abort(400, "Invalid or expired token")

    # Enforce password complexity
    if not meets_password_policy(new_pass):
        abort(400, "Password does not meet requirements")

    reset_req.user.password = hash_password(new_pass)
    reset_req.used = True
    db.save_all([reset_req.user, reset_req])

Liste de contrôle des mesures d'atténuation

7️⃣ A07 - Échecs d'authentification

High

Vue d'ensemble

La confirmation de l'identité d'un utilisateur, l'authentification et la gestion des sessions sont essentielles. Les échecs d'authentification se produisent lorsque les applications autorisent le bourrage d'identifiants, la force brute, les mots de passe faibles ou ont une gestion de session défectueuse telle que la non-rotation des identifiants de session après l'ouverture de la session.

Risque

Les attaquants peuvent accéder aux comptes d'utilisateurs par le biais d'un système automatisé de remplissage de justificatifs d'identité, de la force brute ou du détournement de session. Les comptes compromis peuvent conduire à l'usurpation d'identité, à la fraude et à la violation de données.

Exemple de code vulnérable

Python ❌ Bad
# No brute force protection, weak session handling
@app.route('/login', methods=['POST'])
def login():
    user = db.find_by_email(request.form['email'])
    if user and user.password == request.form['password']:  # Plain comparison!
        session['user'] = user.id  # Session ID not rotated
        return redirect('/dashboard')

Exemple de code sécurisé

Python ✅ Good
from flask_limiter import Limiter

limiter = Limiter(app, default_limits=["100/hour"])

@app.route('/login', methods=['POST'])
@limiter.limit("5/minute")
def login():
    user = db.find_by_email(request.form['email'])
    if not user or not bcrypt.checkpw(
        request.form['password'].encode(), user.password_hash
    ):
        # Generic error to prevent user enumeration
        return "Invalid credentials", 401

    # Rotate session ID after authentication
    session.regenerate()
    session['user'] = user.id

    # Check for MFA requirement
    if user.mfa_enabled:
        return redirect('/mfa-verify')
    return redirect('/dashboard')

Liste de contrôle des mesures d'atténuation

8️⃣ A08 - Défauts d'intégrité des logiciels ou des données

High

Vue d'ensemble

Les défaillances de l'intégrité des logiciels et des données sont liées au code et à l'infrastructure qui ne protègent pas contre les violations de l'intégrité. Il s'agit notamment de la désérialisation non sécurisée, de l'utilisation de CDN ou de plugins non fiables sans vérification de l'intégrité, et de mécanismes de mise à jour automatique sans mises à jour signées.

Risque

Une désérialisation non sécurisée peut conduire à l'exécution de code à distance. Le chargement de scripts à partir de CDN non fiables sans intégrité des sous-ressources (SRI) peut permettre à des attaquants d'injecter du code malveillant dans votre application.

Exemple de code vulnérable

HTML ❌ Bad
<!-- Loading external scripts without integrity checks -->
<script src="https://cdn.example.com/lib.js"></script>

<!-- Insecure deserialization in Python -->
import pickle
data = pickle.loads(user_input)  # Arbitrary code execution!

Exemple de code sécurisé

HTML ✅ Good
<!-- Use Subresource Integrity (SRI) for external scripts -->
<script src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K..."
  crossorigin="anonymous"></script>

# Use safe deserialization in Python
import json
data = json.loads(user_input)  # Safe: only parses JSON data

Liste de contrôle des mesures d'atténuation

9️⃣ A09 - Défauts de journalisation et d'alerte de sécurité

Medium

Vue d'ensemble

En l'absence d'enregistrement, de surveillance et d'alerte suffisants, les violations ne peuvent pas être détectées à temps. Une journalisation insuffisante, une intégration inefficace avec les systèmes de réponse aux incidents et l'absence d'alerte en temps réel permettent aux pirates d'attaquer davantage les systèmes, de maintenir la persistance et d'altérer ou d'extraire des données.

Risque

En l'absence d'une journalisation appropriée, les attaquants peuvent agir sans être détectés pendant de longues périodes. La plupart des études sur les violations montrent que le temps moyen de détection d'une violation dépasse 200 jours, et que cette violation est souvent découverte par des parties externes plutôt que par un contrôle interne.

Exemple de code vulnérable

Python ❌ Bad
# No logging of security-relevant events
@app.route('/login', methods=['POST'])
def login():
    user = authenticate(request.form)
    if not user:
        return "Login failed", 401  # No record of failure
    return redirect('/dashboard')

Exemple de code sécurisé

Python ✅ Good
import logging
from datetime import datetime

security_log = logging.getLogger('security')

@app.route('/login', methods=['POST'])
def login():
    user = authenticate(request.form)
    if not user:
        security_log.warning(
            "LOGIN_FAILED | ip=%s | email=%s | time=%s",
            request.remote_addr,
            request.form.get('email', 'unknown'),
            datetime.utcnow().isoformat(),
        )
        check_brute_force(request.remote_addr)
        return "Invalid credentials", 401

    security_log.info(
        "LOGIN_SUCCESS | user_id=%s | ip=%s",
        user.id, request.remote_addr,
    )
    return redirect('/dashboard')

Liste de contrôle des mesures d'atténuation

🔟 A10 - Mauvaise gestion des conditions exceptionnelles

Medium

Vue d'ensemble

Nouveauté 2025. Les applications qui ne gèrent pas correctement les erreurs, les exceptions et les cas limites peuvent exposer des informations sensibles, entrer dans des états incohérents ou créer des conditions exploitables. Il s'agit notamment de messages d'erreur verbeux en production, d'exceptions non capturées qui contournent les contrôles de sécurité et de conditions de course.

Risque

Une mauvaise gestion des erreurs peut révéler des traces de pile, des détails de base de données ou des chemins internes. Les conditions de course dans les contrôles de sécurité peuvent permettre des attaques de type "temps de contrôle - temps d'utilisation" (TOCTOU), contournant l'autorisation ou la validation du paiement.

Exemple de code vulnérable

Python ❌ Bad
# Exposing internal details in error messages
@app.route('/api/data')
def get_data():
    try:
        result = db.query(request.args['q'])
        return jsonify(result)
    except Exception as e:
        return jsonify({"error": str(e)}), 500  # Leaks DB details!

Exemple de code sécurisé

Python ✅ Good
import uuid, logging

logger = logging.getLogger(__name__)

@app.errorhandler(Exception)
def handle_exception(e):
    error_id = str(uuid.uuid4())
    logger.error("Unhandled exception [%s]: %s", error_id, e, exc_info=True)

    # Return generic error with reference ID for support
    return jsonify({
        "error": "An internal error occurred",
        "reference": error_id,
    }), 500

@app.route('/api/data')
def get_data():
    q = request.args.get('q')
    if not q or not is_valid_query(q):
        return jsonify({"error": "Invalid query parameter"}), 400

    result = db.query(q)
    return jsonify(result)

Liste de contrôle des mesures d'atténuation

📊 Tableau récapitulatif

ID Vulnérabilité Sévérité Principales mesures d'atténuation
A01Contrôle d'accès défaillantCriticalContrôles d'accès côté serveur, refus par défaut, propriété des enregistrements
A02Mauvaise configuration de la sécuritéHighProcessus de durcissement, en-têtes de sécurité, désactivation des valeurs par défaut
A03Défaillances de la chaîne d'approvisionnement en logicielsHighDépendances épinglées, SBOM, analyse des dépendances
A04Défaillances cryptographiquesHighAlgorithmes solides, TLS 1.2+, gestion des clés
A05InjectionCriticalRequêtes paramétrées, codage de sortie, validation d'entrée
A06Insecure DesignHighModélisation des menaces, modèles sécurisés, tests de cas d'abus
A07Défauts d'authentificationHighMFA, protection contre la force brute, rotation de session
A08Défauts d'intégrité des logiciels ou des donnéesHighSRI, mises à jour signées, désérialisation sûre
A09Défauts de journalisation et d'alerte en matière de sécuritéMediumEnregistrement centralisé, alertes en temps réel, réponse aux incidents
A10Mauvaise gestion des conditions exceptionnellesMediumGestionnaire d'erreurs global, messages génériques, prévention TOCTOU