Sécurité des Systèmes Embarqués

Apprenez les principes de sécurité pour protéger les objets connectés : chiffrement, authentification, vulnérabilités et bonnes pratiques de développement sécurisé

Avancé50 min250 XP

En 2016, le botnet Mirai a infecté plus de 600 000 objets connectés (caméras, routeurs) en exploitant des mots de passe par défaut, provoquant une panne Internet massive. La sécurité des systèmes embarqués n'est pas une option, c'est une nécessité absolue !

Objectifs d'apprentissage

  • Comprendre les enjeux de sécurité des systèmes embarqués
  • Identifier les principales vulnérabilités des objets connectés
  • Maîtriser les bases du chiffrement symétrique et asymétrique
  • Implémenter une authentification sécurisée
  • Appliquer les bonnes pratiques de développement sécurisé

Erreurs courantes à éviter

  • Utiliser des mots de passe par défaut (admin/admin)
  • Transmettre des données sensibles en clair (sans chiffrement)
  • Stocker des clés de chiffrement en dur dans le code
  • Négliger les mises à jour de sécurité du firmware

Contenu du cours

Les systèmes embarqués sont exposés à de nombreuses menaces spécifiques liées à leurs contraintes (ressources limitées, accès physique possible, longue durée de vie). **Top 10 des vulnérabilités IoT (OWASP) :** | Rang | Vulnérabilité | Exemple | |------|---------------|---------| | 1 | Mots de passe faibles | admin/admin, root/12345 | | 2 | Services réseau non sécurisés | Telnet ouvert, ports non protégés | | 3 | Interfaces web vulnérables | Injection SQL, XSS | | 4 | Absence de mise à jour sécurisée | Firmware non signé | | 5 | Composants obsolètes | Bibliothèques avec CVE connues | | 6 | Protection insuffisante des données | Stockage en clair | | 7 | Transfert de données non chiffré | HTTP au lieu de HTTPS | | 8 | Gestion d'accès défaillante | Pas de contrôle des permissions | | 9 | Configuration par défaut non sécurisée | Debug activé en production | | 10 | Manque de sécurité physique | JTAG accessible, dump mémoire | **Types d'attaques courantes :** - **Attaque par force brute** : Test de milliers de mots de passe - **Sniffing réseau** : Interception des communications - **Injection de commandes** : Exécution de code malveillant - **Attaque physique** : Extraction de clés depuis la mémoire - **Man-in-the-Middle** : Interception et modification des données
Code Python - Simulation
# Simulation de détection de vulnérabilités IoT
# Scanner de sécurité basique pour objets connectés

import hashlib
import random
import re

class ScannerSecuriteIoT:
    """Simule un scanner de vulnérabilités pour IoT"""

    # Mots de passe faibles courants
    MOTS_DE_PASSE_FAIBLES = [
        "admin", "password", "12345", "123456", "root",
        "default", "guest", "admin123", "password123",
        "1234", "user", "test", "changeme", "00000000"
    ]

    # Ports dangereux
    PORTS_DANGEREUX = {
        21: "FTP (transfert fichiers non chiffré)",
        23: "Telnet (accès distant non chiffré)",
        80: "HTTP (web non chiffré)",
        8080: "HTTP alternatif",
        502: "Modbus (protocole industriel non sécurisé)",
        1883: "MQTT sans TLS"
    }

    def __init__(self):
        self.vulnerabilites = []
        self.score_securite = 100

    def verifier_mot_de_passe(self, mot_de_passe):
        """Analyse la force d'un mot de passe"""
        problemes = []

        # Longueur minimale
        if len(mot_de_passe) < 8:
            problemes.append("Trop court (< 8 caractères)")
            self.score_securite -= 15

        # Mot de passe commun
        if mot_de_passe.lower() in self.MOTS_DE_PASSE_FAIBLES:
            problemes.append("Mot de passe trop commun/par défaut")
            self.score_securite -= 30

        # Complexité
        if not re.search(r'[A-Z]', mot_de_passe):
            problemes.append("Pas de majuscule")
            self.score_securite -= 5
        if not re.search(r'[0-9]', mot_de_passe):
            problemes.append("Pas de chiffre")
            self.score_securite -= 5
        if not re.search(r'[!@#$%^&*(),.?":{}|<>]', mot_de_passe):
            problemes.append("Pas de caractère spécial")
            self.score_securite -= 5

        if problemes:
            self.vulnerabilites.append({
                'type': 'MOT_DE_PASSE_FAIBLE',
                'severite': 'CRITIQUE' if len(problemes) > 2 else 'HAUTE',
                'details': problemes
            })

        return len(problemes) == 0

    def scanner_ports(self, ports_ouverts):
        """Analyse les ports ouverts"""
        ports_problematiques = []

        for port in ports_ouverts:
            if port in self.PORTS_DANGEREUX:
                ports_problematiques.append({
                    'port': port,
                    'service': self.PORTS_DANGEREUX[port]
                })
                self.score_securite -= 10

        if ports_problematiques:
            self.vulnerabilites.append({
                'type': 'PORTS_NON_SECURISES',
                'severite': 'HAUTE',
                'details': ports_problematiques
            })

        return len(ports_problematiques) == 0

    def verifier_chiffrement(self, protocole_utilise):
        """Vérifie l'utilisation du chiffrement"""
        protocoles_securises = ['HTTPS', 'TLS', 'SSL', 'MQTTS', 'WSS', 'SSH']
        protocoles_non_securises = ['HTTP', 'FTP', 'Telnet', 'MQTT']

        if protocole_utilise.upper() in protocoles_non_securises:
            self.vulnerabilites.append({
                'type': 'TRANSFERT_NON_CHIFFRE',
                'severite': 'CRITIQUE',
                'details': f"Le protocole {protocole_utilise} n'est pas chiffré"
            })
            self.score_securite -= 25
            return False

        return protocole_utilise.upper() in protocoles_securises

    def verifier_firmware(self, version, derniere_version, signe_numeriquement):
        """Vérifie l'état du firmware"""
        if version != derniere_version:
            self.vulnerabilites.append({
                'type': 'FIRMWARE_OBSOLETE',
                'severite': 'MOYENNE',
                'details': f"Version {version} < {derniere_version}"
            })
            self.score_securite -= 10

        if not signe_numeriquement:
            self.vulnerabilites.append({
                'type': 'FIRMWARE_NON_SIGNE',
                'severite': 'HAUTE',
                'details': "Le firmware n'est pas signé numériquement"
            })
            self.score_securite -= 15

    def generer_rapport(self):
        """Génère un rapport de sécurité"""
        self.score_securite = max(0, self.score_securite)

        print("\n" + "="*60)
        print("     RAPPORT D'AUDIT SÉCURITÉ IoT")
        print("="*60)

        # Score global
        if self.score_securite >= 80:
            niveau = "🟢 BON"
        elif self.score_securite >= 50:
            niveau = "🟡 MOYEN"
        else:
            niveau = "🔴 CRITIQUE"

        print(f"\n📊 SCORE DE SÉCURITÉ : {self.score_securite}/100 ({niveau})")

        # Vulnérabilités détectées
        print(f"\n🔍 VULNÉRABILITÉS DÉTECTÉES : {len(self.vulnerabilites)}")

        for vuln in self.vulnerabilites:
            icone = "🔴" if vuln['severite'] == 'CRITIQUE' else "🟠" if vuln['severite'] == 'HAUTE' else "🟡"
            print(f"\n{icone} [{vuln['severite']}] {vuln['type']}")
            if isinstance(vuln['details'], list):
                for detail in vuln['details']:
                    if isinstance(detail, dict):
                        print(f"   - Port {detail['port']}: {detail['service']}")
                    else:
                        print(f"   - {detail}")
            else:
                print(f"   - {vuln['details']}")

        # Recommandations
        print("\n" + "="*60)
        print("📋 RECOMMANDATIONS")
        print("="*60)

        if self.score_securite < 100:
            print("\n1. Changer immédiatement les mots de passe par défaut")
            print("2. Désactiver les services non nécessaires (Telnet, FTP)")
            print("3. Utiliser HTTPS/TLS pour toutes les communications")
            print("4. Mettre à jour le firmware vers la dernière version")
            print("5. Activer la signature numérique du firmware")

        print("\n" + "="*60)

# Démonstration du scanner
print("=== SCAN DE SÉCURITÉ D'UN OBJET CONNECTÉ ===\n")

scanner = ScannerSecuriteIoT()

# Simuler un scan d'appareil IoT (caméra IP par exemple)
print("Appareil : Caméra IP GeneriCam v2.0")
print("Adresse IP : 192.168.1.42")
print("\n--- Analyse en cours ---\n")

# Test 1 : Mot de passe
print("1. Vérification du mot de passe...")
mdp_ok = scanner.verifier_mot_de_passe("admin123")
print(f"   Résultat : {'✅ OK' if mdp_ok else '❌ FAIBLE'}")

# Test 2 : Ports ouverts
print("\n2. Scan des ports...")
ports = [22, 23, 80, 443, 554]  # SSH, Telnet, HTTP, HTTPS, RTSP
ports_ok = scanner.scanner_ports(ports)
print(f"   Ports ouverts : {ports}")
print(f"   Résultat : {'✅ OK' if ports_ok else '❌ PORTS DANGEREUX'}")

# Test 3 : Chiffrement
print("\n3. Vérification du chiffrement...")
chiffre = scanner.verifier_chiffrement("HTTP")
print(f"   Protocole : HTTP")
print(f"   Résultat : {'✅ CHIFFRÉ' if chiffre else '❌ NON CHIFFRÉ'}")

# Test 4 : Firmware
print("\n4. Analyse du firmware...")
scanner.verifier_firmware("2.0.1", "2.3.5", signe_numeriquement=False)

# Rapport final
scanner.generer_rapport()

Quiz de validation

1. Quelle attaque a compromis 600 000 objets connectés en 2016 en exploitant des mots de passe par défaut ?

2. Quel type de chiffrement utilise la même clé pour chiffrer et déchiffrer ?

3. Pourquoi ECDSA est-il préféré à RSA pour les systèmes embarqués ?

4. Dans l'authentification challenge-response, que ne transite JAMAIS sur le réseau ?

5. Que signifie le principe 'Fail-secure' en sécurité ?

Pixel