Aller au contenu

B3.4 - Sécurité des Applications Web

Protection des données et sécurisation des services - BTS SIO

🎯 Objectifs du cours

À l'issue de ce cours, vous serez capable de : - Comprendre les protocoles de sécurisation web (HTTPS, TLS) - Implémenter des mécanismes d'authentification et d'autorisation - Protéger les données personnelles selon le RGPD - Sécuriser les communications et les sessions utilisateur


🔒 Protocoles de sécurisation

HTTPS (HyperText Transfer Protocol Secure)
Version sécurisée du protocole HTTP utilisant TLS/SSL pour chiffrer les communications entre le client et le serveur, garantissant confidentialité, intégrité et authentification.

Comparaison HTTP vs HTTPS

🔓
HTTP
  • Port 80
  • Données en clair
  • Vulnérable aux écoutes
  • Pas d'authentification du serveur
  • Risque de modification des données
🔒
HTTPS
  • Port 443
  • Données chiffrées
  • Protection contre l'écoute
  • Certificat serveur
  • Intégrité des données garantie

Processus de connexion TLS

1. Client Hello
Le client envoie sa version TLS, les algorithmes supportés et un nombre aléatoire.
2. Server Hello
Le serveur répond avec sa version TLS, l'algorithme choisi, son certificat et un nombre aléatoire.
3. Vérification du certificat
Le client vérifie la validité du certificat serveur auprès d'une autorité de certification.
4. Échange de clés
Génération d'une clé de session symétrique pour chiffrer les communications.
5. Communication sécurisée
Toutes les données sont chiffrées avec la clé de session.

Configuration HTTPS avec Python Flask

Serveur Flask avec HTTPS
from flask import Flask, request, session, redirect, url_for
import ssl

app = Flask(__name__)
app.secret_key = 'votre_cle_secrete_tres_longue_et_aleatoire'

@app.route('/')
def index():
    return '''
    <h1>Serveur HTTPS sécurisé</h1>
    <p>Cette connexion est chiffrée !</p>
    <a href="/login">Se connecter</a>
    '''

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        # Vérification sécurisée (à implémenter)
        if verify_credentials(username, password):
            session['user'] = username
            return redirect(url_for('dashboard'))
        else:
            return 'Identifiants incorrects', 401

    return '''
    <form method="post">
        <input type="text" name="username" placeholder="Nom d'utilisateur" required>
        <input type="password" name="password" placeholder="Mot de passe" required>
        <button type="submit">Se connecter</button>
    </form>
    '''

@app.route('/dashboard')
def dashboard():
    if 'user' not in session:
        return redirect(url_for('login'))
    return f'Bienvenue {session["user"]} !'

def verify_credentials(username, password):
    # Implémentation sécurisée avec hachage
    # Ne jamais stocker les mots de passe en clair !
    return True  # Exemple simplifié

if __name__ == '__main__':
    # Configuration SSL/TLS
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.load_cert_chain('certificat.pem', 'cle_privee.pem')

    app.run(host='0.0.0.0', port=443, ssl_context=context, debug=False)

🔐 Authentification et autorisation

Authentification vs Autorisation
Authentification : Vérifier l'identité de l'utilisateur ("Qui êtes-vous ?")
Autorisation : Vérifier les permissions de l'utilisateur ("Que pouvez-vous faire ?")

Méthodes d'authentification

🔑 Authentification basique

Nom d'utilisateur et mot de passe. Simple mais nécessite HTTPS.

🎫 Authentification par token

JWT (JSON Web Token) pour les API et applications modernes.

📱 Authentification multi-facteurs (MFA)

Combinaison de plusieurs facteurs : mot de passe + SMS/app.

🔗 OAuth 2.0

Délégation d'authentification via des services tiers (Google, Facebook).

Implémentation sécurisée des mots de passe

Gestion sécurisée des mots de passe
import hashlib
import secrets
import bcrypt
from werkzeug.security import generate_password_hash, check_password_hash

class UserManager:
    def __init__(self):
        self.users = {}  # En production : base de données

    def hash_password_bcrypt(self, password):
        """Hachage sécurisé avec bcrypt (recommandé)"""
        salt = bcrypt.gensalt()
        hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
        return hashed

    def verify_password_bcrypt(self, password, hashed):
        """Vérification avec bcrypt"""
        return bcrypt.checkpw(password.encode('utf-8'), hashed)

    def hash_password_werkzeug(self, password):
        """Alternative avec Werkzeug"""
        return generate_password_hash(password, method='pbkdf2:sha256', salt_length=16)

    def verify_password_werkzeug(self, password, hashed):
        """Vérification avec Werkzeug"""
        return check_password_hash(hashed, password)

    def create_user(self, username, password, email):
        """Créer un nouvel utilisateur"""
        if username in self.users:
            raise ValueError("Utilisateur déjà existant")

        # Validation du mot de passe
        if not self.is_strong_password(password):
            raise ValueError("Mot de passe trop faible")

        # Hachage sécurisé
        hashed_password = self.hash_password_bcrypt(password)

        self.users[username] = {
            'password_hash': hashed_password,
            'email': email,
            'created_at': datetime.now(),
            'last_login': None,
            'failed_attempts': 0,
            'locked_until': None
        }

        return True

    def authenticate(self, username, password):
        """Authentifier un utilisateur"""
        user = self.users.get(username)
        if not user:
            return False

        # Vérifier si le compte est verrouillé
        if user['locked_until'] and datetime.now() < user['locked_until']:
            raise Exception("Compte temporairement verrouillé")

        # Vérifier le mot de passe
        if self.verify_password_bcrypt(password, user['password_hash']):
            # Réinitialiser les tentatives échouées
            user['failed_attempts'] = 0
            user['locked_until'] = None
            user['last_login'] = datetime.now()
            return True
        else:
            # Incrémenter les tentatives échouées
            user['failed_attempts'] += 1

            # Verrouiller après 5 tentatives
            if user['failed_attempts'] >= 5:
                user['locked_until'] = datetime.now() + timedelta(minutes=30)

            return False

    def is_strong_password(self, password):
        """Vérifier la force du mot de passe"""
        if len(password) < 8:
            return False

        has_upper = any(c.isupper() for c in password)
        has_lower = any(c.islower() for c in password)
        has_digit = any(c.isdigit() for c in password)
        has_special = any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in password)

        return has_upper and has_lower and has_digit and has_special

# Exemple d'utilisation
user_manager = UserManager()

try:
    user_manager.create_user("alice", "MonMotDePasse123!", "alice@example.com")
    print("Utilisateur créé avec succès")

    if user_manager.authenticate("alice", "MonMotDePasse123!"):
        print("Authentification réussie")
    else:
        print("Échec de l'authentification")

except ValueError as e:
    print(f"Erreur : {e}")

Gestion des sessions sécurisées

Sessions sécurisées avec Flask
from flask import Flask, session, request, jsonify
import secrets
import time

app = Flask(__name__)
app.secret_key = secrets.token_hex(32)  # Clé aléatoire sécurisée

# Configuration sécurisée des sessions
app.config.update(
    SESSION_COOKIE_SECURE=True,      # HTTPS uniquement
    SESSION_COOKIE_HTTPONLY=True,    # Pas d'accès JavaScript
    SESSION_COOKIE_SAMESITE='Lax',   # Protection CSRF
    PERMANENT_SESSION_LIFETIME=1800  # 30 minutes
)

class SessionManager:
    def __init__(self):
        self.active_sessions = {}

    def create_session(self, user_id):
        """Créer une nouvelle session"""
        session_id = secrets.token_urlsafe(32)
        session_data = {
            'user_id': user_id,
            'created_at': time.time(),
            'last_activity': time.time(),
            'ip_address': request.remote_addr,
            'user_agent': request.headers.get('User-Agent', '')
        }

        self.active_sessions[session_id] = session_data
        session['session_id'] = session_id
        session.permanent = True

        return session_id

    def validate_session(self, session_id):
        """Valider une session existante"""
        if session_id not in self.active_sessions:
            return False

        session_data = self.active_sessions[session_id]
        current_time = time.time()

        # Vérifier l'expiration (30 minutes d'inactivité)
        if current_time - session_data['last_activity'] > 1800:
            self.destroy_session(session_id)
            return False

        # Vérifier l'IP (optionnel, peut poser problème avec les proxies)
        if session_data['ip_address'] != request.remote_addr:
            # Log de sécurité
            print(f"Changement d'IP détecté pour la session {session_id}")

        # Mettre à jour l'activité
        session_data['last_activity'] = current_time
        return True

    def destroy_session(self, session_id):
        """Détruire une session"""
        if session_id in self.active_sessions:
            del self.active_sessions[session_id]

        session.clear()

    def get_user_id(self, session_id):
        """Récupérer l'ID utilisateur d'une session"""
        if session_id in self.active_sessions:
            return self.active_sessions[session_id]['user_id']
        return None

session_manager = SessionManager()

@app.before_request
def check_session():
    """Vérifier la session avant chaque requête"""
    if request.endpoint in ['login', 'static']:
        return  # Pas de vérification pour ces endpoints

    session_id = session.get('session_id')
    if not session_id or not session_manager.validate_session(session_id):
        return jsonify({'error': 'Session invalide'}), 401

@app.route('/logout')
def logout():
    """Déconnexion sécurisée"""
    session_id = session.get('session_id')
    if session_id:
        session_manager.destroy_session(session_id)

    return jsonify({'message': 'Déconnexion réussie'})

🛡️ Protection contre les vulnérabilités web

Top 10 OWASP des vulnérabilités

Rang Vulnérabilité Description Protection
1 Injection SQL, NoSQL, LDAP injection Requêtes préparées, validation
2 Authentification cassée Sessions, mots de passe faibles MFA, sessions sécurisées
3 Exposition de données Données sensibles non protégées Chiffrement, HTTPS
4 XXE XML External Entity Désactiver les entités externes
5 Contrôle d'accès cassé Autorisations mal configurées Principe du moindre privilège
6 Configuration de sécurité Paramètres par défaut non sécurisés Durcissement, mise à jour
7 XSS Cross-Site Scripting Échappement, CSP
8 Désérialisation Objets non fiables Validation, signature
9 Composants vulnérables Bibliothèques obsolètes Mise à jour régulière
10 Logging insuffisant Détection d'incidents limitée Logs détaillés, monitoring

Protection contre les injections SQL

Prévention des injections SQL
import sqlite3
from flask import Flask, request, jsonify

app = Flask(__name__)

class DatabaseManager:
    def __init__(self, db_path):
        self.db_path = db_path
        self.init_database()

    def init_database(self):
        """Initialiser la base de données"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        cursor.execute('''
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY,
                username TEXT UNIQUE NOT NULL,
                email TEXT NOT NULL,
                password_hash TEXT NOT NULL,
                role TEXT DEFAULT 'user'
            )
        ''')

        conn.commit()
        conn.close()

    def get_user_vulnerable(self, username):
        """VULNÉRABLE - Ne jamais faire cela !"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        # DANGER : Injection SQL possible
        query = f"SELECT * FROM users WHERE username = '{username}'"
        cursor.execute(query)

        result = cursor.fetchone()
        conn.close()
        return result

    def get_user_secure(self, username):
        """SÉCURISÉ - Utilisation de requêtes préparées"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        # Sécurisé : paramètres liés
        cursor.execute("SELECT * FROM users WHERE username = ?", (username,))

        result = cursor.fetchone()
        conn.close()
        return result

    def search_users_secure(self, search_term, role=None):
        """Recherche sécurisée avec paramètres multiples"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        query = "SELECT id, username, email, role FROM users WHERE username LIKE ?"
        params = [f"%{search_term}%"]

        if role:
            query += " AND role = ?"
            params.append(role)

        cursor.execute(query, params)
        results = cursor.fetchall()
        conn.close()

        return results

db = DatabaseManager('app.db')

@app.route('/user/<username>')
def get_user(username):
    """Endpoint sécurisé pour récupérer un utilisateur"""
    # Validation d'entrée
    if not username or len(username) > 50:
        return jsonify({'error': 'Nom d'utilisateur invalide'}), 400

    # Utilisation de la méthode sécurisée
    user = db.get_user_secure(username)

    if user:
        return jsonify({
            'id': user[0],
            'username': user[1],
            'email': user[2],
            'role': user[4]
        })
    else:
        return jsonify({'error': 'Utilisateur non trouvé'}), 404

@app.route('/search')
def search_users():
    """Recherche d'utilisateurs avec validation"""
    search_term = request.args.get('q', '').strip()
    role = request.args.get('role', '').strip()

    # Validation des paramètres
    if not search_term or len(search_term) < 2:
        return jsonify({'error': 'Terme de recherche trop court'}), 400

    if role and role not in ['user', 'admin', 'moderator']:
        return jsonify({'error': 'Rôle invalide'}), 400

    results = db.search_users_secure(search_term, role)

    return jsonify({
        'users': [
            {
                'id': user[0],
                'username': user[1],
                'email': user[2],
                'role': user[3]
            }
            for user in results
        ]
    })

Protection XSS et CSP

Protection contre XSS
from flask import Flask, render_template_string, request, escape
from markupsafe import Markup
import html
import re

app = Flask(__name__)

class XSSProtection:
    @staticmethod
    def sanitize_input(user_input):
        """Nettoyer les entrées utilisateur"""
        if not user_input:
            return ""

        # Échapper les caractères HTML
        sanitized = html.escape(user_input)

        # Supprimer les scripts potentiels
        sanitized = re.sub(r'<script[^>]*>.*?</script>', '', sanitized, flags=re.IGNORECASE | re.DOTALL)

        return sanitized

    @staticmethod
    def validate_url(url):
        """Valider une URL pour éviter les redirections malveillantes"""
        if not url:
            return False

        # Autoriser seulement les URLs relatives ou HTTPS
        if url.startswith('/') or url.startswith('https://'):
            return True

        return False

@app.route('/comment', methods=['POST'])
def add_comment():
    """Ajouter un commentaire avec protection XSS"""
    comment = request.form.get('comment', '')

    # Nettoyer l'entrée
    clean_comment = XSSProtection.sanitize_input(comment)

    # Validation supplémentaire
    if len(clean_comment) > 1000:
        return "Commentaire trop long", 400

    # Sauvegarder en base (exemple)
    # db.save_comment(clean_comment)

    return f"Commentaire ajouté : {clean_comment}"

@app.after_request
def add_security_headers(response):
    """Ajouter des en-têtes de sécurité"""
    # Content Security Policy
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self' 'unsafe-inline'; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data: https:; "
        "font-src 'self'; "
        "connect-src 'self'; "
        "frame-ancestors 'none';"
    )

    # Autres en-têtes de sécurité
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'

    return response

🔐 Protection des données personnelles

RGPD (Règlement Général sur la Protection des Données)
Règlement européen entré en vigueur en 2018, qui encadre le traitement des données personnelles et renforce les droits des individus sur leurs données.

Principes fondamentaux du RGPD

🎯 Finalité
Les données doivent être collectées pour des finalités déterminées, explicites et légitimes.
📏 Minimisation
Collecter uniquement les données nécessaires à la finalité poursuivie.
⏰ Conservation limitée
Les données ne doivent pas être conservées plus longtemps que nécessaire.
🔒 Sécurité
Mettre en place des mesures techniques et organisationnelles appropriées.

Droits des personnes concernées

ℹ️
Droit à l'information
Être informé de la collecte et du traitement de ses données personnelles.
👁️
Droit d'accès
Obtenir une copie de ses données personnelles et des informations sur leur traitement.
✏️
Droit de rectification
Demander la correction de données inexactes ou incomplètes.
🗑️
Droit à l'effacement
Demander la suppression de ses données dans certaines conditions.
📦
Droit à la portabilité
Récupérer ses données dans un format structuré et les transférer.
🚫
Droit d'opposition
S'opposer au traitement de ses données pour des raisons légitimes.

Implémentation RGPD en Python

Gestion RGPD avec Python
from datetime import datetime, timedelta
import json
import hashlib

class GDPRManager:
    def __init__(self):
        self.data_retention_policies = {
            'user_logs': timedelta(days=365),
            'marketing_data': timedelta(days=1095),  # 3 ans
            'financial_data': timedelta(days=2555),  # 7 ans
            'session_data': timedelta(hours=24)
        }

        self.consent_records = {}
        self.data_processing_log = []

    def record_consent(self, user_id, purpose, consent_given, ip_address):
        """Enregistrer le consentement utilisateur"""
        consent_record = {
            'user_id': user_id,
            'purpose': purpose,
            'consent_given': consent_given,
            'timestamp': datetime.now().isoformat(),
            'ip_address': self.hash_ip(ip_address),
            'version': '1.0'  # Version de la politique de confidentialité
        }

        if user_id not in self.consent_records:
            self.consent_records[user_id] = []

        self.consent_records[user_id].append(consent_record)

        # Log de l'activité
        self.log_data_processing(user_id, 'consent_recorded', purpose)

    def hash_ip(self, ip_address):
        """Hasher l'adresse IP pour la pseudonymisation"""
        return hashlib.sha256(ip_address.encode()).hexdigest()[:16]

    def log_data_processing(self, user_id, action, purpose, data_type=None):
        """Logger les activités de traitement de données"""
        log_entry = {
            'user_id': user_id,
            'action': action,
            'purpose': purpose,
            'data_type': data_type,
            'timestamp': datetime.now().isoformat(),
            'processor': 'system'
        }

        self.data_processing_log.append(log_entry)

    def export_user_data(self, user_id):
        """Exporter toutes les données d'un utilisateur (portabilité)"""
        user_data = {
            'user_id': user_id,
            'export_date': datetime.now().isoformat(),
            'consent_records': self.consent_records.get(user_id, []),
            'processing_log': [
                log for log in self.data_processing_log 
                if log['user_id'] == user_id
            ]
        }

        # Ajouter d'autres données utilisateur depuis la base
        # user_data.update(self.get_user_profile(user_id))
        # user_data.update(self.get_user_orders(user_id))

        self.log_data_processing(user_id, 'data_exported', 'user_request')

        return json.dumps(user_data, indent=2, ensure_ascii=False)

    def delete_user_data(self, user_id, reason='user_request'):
        """Supprimer les données d'un utilisateur (droit à l'effacement)"""
        # Vérifier si la suppression est autorisée
        if not self.can_delete_user_data(user_id, reason):
            raise Exception("Suppression non autorisée pour des raisons légales")

        # Supprimer les données personnelles
        # self.delete_user_profile(user_id)
        # self.anonymize_user_orders(user_id)

        # Conserver les logs de consentement (obligation légale)
        self.log_data_processing(user_id, 'data_deleted', reason)

        return True

    def can_delete_user_data(self, user_id, reason):
        """Vérifier si les données peuvent être supprimées"""
        # Vérifier les obligations légales de conservation
        # Par exemple, données financières à conserver 7 ans

        # Vérifier s'il y a des litiges en cours
        # if self.has_pending_legal_case(user_id):
        #     return False

        return True

    def anonymize_expired_data(self):
        """Anonymiser les données expirées selon les politiques de rétention"""
        current_time = datetime.now()

        for data_type, retention_period in self.data_retention_policies.items():
            expiry_date = current_time - retention_period

            # Identifier et anonymiser les données expirées
            # self.anonymize_data_by_type(data_type, expiry_date)

            print(f"Données {data_type} antérieures à {expiry_date} anonymisées")

    def generate_privacy_report(self, user_id):
        """Générer un rapport de confidentialité pour un utilisateur"""
        consent_history = self.consent_records.get(user_id, [])
        processing_activities = [
            log for log in self.data_processing_log 
            if log['user_id'] == user_id
        ]

        report = {
            'user_id': user_id,
            'report_date': datetime.now().isoformat(),
            'active_consents': [
                consent for consent in consent_history 
                if consent['consent_given']
            ],
            'data_processing_summary': {
                'total_activities': len(processing_activities),
                'last_activity': max(
                    (log['timestamp'] for log in processing_activities), 
                    default='Aucune activité'
                )
            },
            'retention_status': self.get_retention_status(user_id)
        }

        return report

    def get_retention_status(self, user_id):
        """Obtenir le statut de rétention des données"""
        # Calculer quand les différents types de données expireront
        current_time = datetime.now()

        status = {}
        for data_type, retention_period in self.data_retention_policies.items():
            # En pratique, récupérer la date de création des données
            # creation_date = self.get_data_creation_date(user_id, data_type)
            # expiry_date = creation_date + retention_period

            status[data_type] = {
                'retention_period_days': retention_period.days,
                'status': 'active'  # ou 'expired', 'anonymized'
            }

        return status

# Exemple d'utilisation
gdpr_manager = GDPRManager()

# Enregistrer un consentement
gdpr_manager.record_consent(
    user_id='user123',
    purpose='marketing',
    consent_given=True,
    ip_address='192.168.1.1'
)

# Exporter les données d'un utilisateur
user_data_export = gdpr_manager.export_user_data('user123')
print("Données exportées :", user_data_export)

# Générer un rapport de confidentialité
privacy_report = gdpr_manager.generate_privacy_report('user123')
print("Rapport de confidentialité :", privacy_report)

🔍 Monitoring et détection d'incidents

### Mise en place de logs de sécurité
Système de logging sécurisé
import logging
import json
from datetime import datetime
from flask import request, g
import hashlib

class SecurityLogger:
    def __init__(self, log_file='security.log'):
        self.logger = logging.getLogger('security')
        self.logger.setLevel(logging.INFO)

        # Handler pour fichier
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(logging.INFO)

        # Format JSON pour faciliter l'analyse
        formatter = logging.Formatter('%(message)s')
        file_handler.setFormatter(formatter)

        self.logger.addHandler(file_handler)

    def log_security_event(self, event_type, user_id=None, details=None, severity='INFO'):
        """Logger un événement de sécurité"""
        event = {
            'timestamp': datetime.now().isoformat(),
            'event_type': event_type,
            'severity': severity,
            'user_id': user_id,
            'ip_address': self.get_client_ip(),
            'user_agent': request.headers.get('User-Agent', ''),
            'endpoint': request.endpoint,
            'method': request.method,
            'details': details or {}
        }

        self.logger.info(json.dumps(event))

    def get_client_ip(self):
        """Obtenir l'IP du client en tenant compte des proxies"""
        if request.headers.get('X-Forwarded-For'):
            return request.headers.get('X-Forwarded-For').split(',')[0].strip()
        elif request.headers.get('X-Real-IP'):
            return request.headers.get('X-Real-IP')
        else:
            return request.remote_addr

    def log_login_attempt(self, username, success, reason=None):
        """Logger une tentative de connexion"""
        self.log_security_event(
            event_type='login_attempt',
            user_id=username,
            details={
                'success': success,
                'reason': reason
            },
            severity='WARNING' if not success else 'INFO'
        )

    def log_permission_denied(self, user_id, resource, action):
        """Logger un accès refusé"""
        self.log_security_event(
            event_type='permission_denied',
            user_id=user_id,
            details={
                'resource': resource,
                'action': action
            },
            severity='WARNING'
        )

    def log_suspicious_activity(self, user_id, activity_type, details):
        """Logger une activité suspecte"""
        self.log_security_event(
            event_type='suspicious_activity',
            user_id=user_id,
            details={
                'activity_type': activity_type,
                'details': details
            },
            severity='CRITICAL'
        )

# Intégration avec Flask
security_logger = SecurityLogger()

@app.before_request
def log_request():
    """Logger les requêtes sensibles"""
    sensitive_endpoints = ['login', 'admin', 'api']

    if any(endpoint in request.endpoint for endpoint in sensitive_endpoints):
        security_logger.log_security_event(
            event_type='sensitive_endpoint_access',
            details={'endpoint': request.endpoint}
        )

@app.after_request
def log_response(response):
    """Logger les réponses d'erreur"""
    if response.status_code >= 400:
        security_logger.log_security_event(
            event_type='error_response',
            details={
                'status_code': response.status_code,
                'endpoint': request.endpoint
            },
            severity='WARNING' if response.status_code < 500 else 'ERROR'
        )

    return response

📚 Pour aller plus loin

🔗 Ressources complémentaires :
  • OWASP Top 10 : Guide des vulnérabilités web les plus critiques
  • Let's Encrypt : Certificats SSL/TLS gratuits
  • CNIL : Guide RGPD et protection des données
  • Mozilla Observatory : Test de sécurité des sites web
  • Burp Suite : Outil de test de sécurité des applications web

✅ Points clés à retenir

  1. HTTPS : Obligatoire pour protéger les communications
  2. Authentification forte : MFA, sessions sécurisées, mots de passe robustes
  3. Protection XSS/CSRF : Validation, échappement, CSP
  4. RGPD : Consentement, droits des utilisateurs, minimisation des données
  5. Monitoring : Logs de sécurité, détection d'incidents
🎓 Prochaine étape : Dans le cours B3.5, nous découvrirons les outils et méthodologies de sécurité (OWASP, Burp Suite, tests de pénétration).