Laborator 5: Securizarea unui proiect embedded pe ESP32-CAM

În acest laborator ne vom concentra pe securizarea completă a sistemului, de la layer-ul de transport (TLS) până la codul sursă și hardware-ul propriu-zis.

Obiective

  1. Implementarea comunicației criptate (MQTT peste TLS).
  2. Analiza securității codului folosind unelte automate (bandit, cppcheck).
  3. Mecanisme de protecție a firmware-ului (Secure Boot, Flash Encryption).

Partea 1: Securizarea transportului (TLS/SSL)

Până acum, traficul MQTT (inclusiv imaginile) circulă în clar prin rețea. Oricine conectat la aceeași rețea poate intercepta datele cu un simplu Wireshark. Vom securiza comunicația folosind TLS (Transport Layer Security).

1.1 Generarea certificatelor (OpenSSL)

Vom crea o Autoritate de Certificare (CA) proprie care va semna certificatele serverului.

Modern OpenSSL validează adresele IP prin câmpul Subject Alternative Name (SAN), nu doar prin Common Name (CN). Comenzile de mai jos includ acest câmp.

Creați un director certs în rădăcina proiectului:

mkdir certs && cd certs

Pasul 1: Generarea CA (Certificate Authority)

# Cheia privată a CA
openssl genrsa -out ca.key 2048
 
# Certificatul CA (auto-semnat, valabil 10 ani)
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt \
    -subj "/CN=SS-Project-CA"

Pasul 2: Generarea certificatului pentru broker (Server)

Înlocuiți ADRESA_IP_BROKER cu IP-ul real al mașinii pe care rulează Mosquitto (ex: 192.168.1.100):

# Cheia privată a serverului
openssl genrsa -out server.key 2048
 
# Cererea de semnare (CSR) cu Subject Alternative Name
openssl req -new -key server.key -out server.csr \
    -subj "/CN=ADRESA_IP_BROKER" \
    -addext "subjectAltName=IP:ADRESA_IP_BROKER"
 
# Semnarea certificatului de către CA (valabil 1 an)
openssl x509 -req -in server.csr \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out server.crt -days 365 -sha256 \
    -copy_extensions copyall

Verificare

# Verificați că certificatul serverului conține SAN-ul corect
openssl x509 -in server.crt -text -noout | grep -A1 "Subject Alternative Name"
# Ar trebui să vedeți: IP Address:ADRESA_IP_BROKER

1.2 Configurarea Mosquitto cu TLS

Creați un fișier mosquitto_secure.conf:

mosquitto_secure.conf
listener 8883
cafile ./certs/ca.crt
certfile ./certs/server.crt
keyfile ./certs/server.key
require_certificate false

Porniți brokerul securizat:

sudo systemctl stop mosquitto.service
mosquitto -c mosquitto_secure.conf -v

Ar trebui să vedeți în log: Opening ipv4 listen socket on port 8883.

1.3 Actualizarea receiver-ului Python

Adăugați o singură linie înainte de client.connect():

# Activăm TLS cu certificatul CA
client.tls_set(ca_certs="certs/ca.crt")
 
# Schimbăm portul la 8883
client.connect(BROKER, 8883, 60)

Testați: rulați receiver-ul și verificați că se conectează fără erori.

1.4 Actualizarea firmware-ului ESP32

Modificați main.cpp pentru a folosi WiFiClientSecure:

main.cpp
#include <WiFiClientSecure.h>  // Înlocuiește <WiFi.h> pentru TLS
 
// Copiați conținutul fișierului ca.crt aici (inclusiv BEGIN/END):
const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDaz... (conținutul certificatului vostru) ...\n" \
"-----END CERTIFICATE-----\n";
 
// Înlocuiți WiFiClient cu WiFiClientSecure
WiFiClientSecure espClient;
 
void setup() {
  // ... (după conectarea la WiFi)
 
  // Încărcăm certificatul CA
  espClient.setCACert(ca_cert);
 
  // Portul devine 8883
  client.setServer(mqtt_server, 8883);
  // ...
}

Debugging: Dacă ESP32 refuză conexiunea cu SSL handshake failed, verificați:

  1. CN/SAN-ul certificatului corespunde IP-ului brokerului.
  2. Ceasul ESP32 este aproximativ corect (certificatele au dată de expirare).
  3. Ca test temporar, puteți folosi espClient.setInsecure() pentru a dezactiva validarea.

Partea 2: Analiza statică a codului (SAST)

Folosim unelte automate pentru a găsi vulnerabilități fără a rula codul.

2.1 Bandit (Python)

Analizează codul Python pentru probleme de securitate.

pip install bandit
bandit -r receiver/

Ce caută Bandit?

  • Hardcoded secrets: Parole sau chei scrise direct în cod.
  • Weak cryptography: Algoritmi învechiți (MD5, SHA1 pentru hashing de securitate).
  • Subprocess injection: Apeluri os.system() sau subprocess cu input nesanitizat.

2.2 Cppcheck (C/C++)

Analizează codul firmware-ului pentru bug-uri și vulnerabilități.

sudo apt-get install cppcheck
cppcheck --enable=all --inconclusive --std=c++11 camera/src/

Ce caută Cppcheck?

  • Buffer overflows: Scrierea în afara limitelor unui array (critic pe dispozitive embedded!).
  • Uninitialized variables: Comportament nedefinit care poate cauza crash-uri aleatorii.
  • Memory leaks: Pierderi de memorie care duc la blocarea dispozitivului în timp.
  • Null pointer dereference: Accesarea unui pointer nul.

Partea 3: Securitatea hardware (ESP32)

Chiar dacă comunicația este criptată și codul este curat, un atacator cu acces fizic la dispozitiv poate extrage firmware-ul sau cheile TLS din memoria flash.

3.1 Flash encryption

Criptează conținutul memoriei flash (cod + date) cu o cheie AES stocată în eFuse (memorie write-once din cip, imposibil de citit prin software).

  • Dacă un atacator copiază flash-ul fizic, va vedea doar date criptate.
  • Dispozitivul decriptează transparent codul la boot.

3.2 Secure Boot

Verifică semnătura digitală a firmware-ului la fiecare pornire.

  • Dezvoltatorul semnează firmware-ul cu o cheie privată.
  • Bootloader-ul verifică semnătura — dacă nu se potrivește (firmware modificat), dispozitivul refuză să pornească.
  • Previne instalarea de firmware malițios.

3.3 Verificarea stării cu ''espefuse.py''

Putem inspecta starea de securitate a unui cip fără a modifica nimic:

espefuse.py --port /dev/ttyACM0 summary

Urmăriți secțiunea Security fuses:

  • FLASH_CRYPT_CNT: Contor criptare flash (0 = dezactivat).
  • ABS_DONE_0: Secure Boot (0 = dezactivat, 1 = activat).

PERICOL DE BRICK-UIRE PERMANENTĂ A PLĂCUȚEI DE LABORATOR!

Comenzile espefuse.py burn_efuse, espefuse.py burn_key și espefuse.py write_protect_efuse sunt IREVERSIBILE. eFuse-urile sunt memorii one-time programmable — odată scrise, nu mai pot fi modificate sau resetate. O comandă greșită va face plăcuța complet inutilizabilă (bricked).

Reguli stricte:

  1. Folosiți NUMAI comanda summary (doar citire).
  2. NU rulați NICIO altă comandă `espefuse.py` fără aprobarea asistentului.
  3. Dacă vedeți un tutorial online care vă cere să scrieți eFuse-uri, IGNORAȚI-L! Acele operații sunt pentru producția de serie, nu pentru laborator.
  4. Studenții care distrug plăcuțe prin neglijență vor fi responsabili de înlocuirea lor.

Exerciții

  1. Implementare TLS: Urmăriți pașii din Partea 1 pentru a securiza comunicația. Verificați cu Wireshark că traficul pe portul 8883 este criptat (comparativ cu portul 1883 din laboratorul anterior).
  2. Secret management: Modificați main.cpp și receiver.py astfel încât credențialele să nu mai fie hardcodate:
    • Python: Citiți din variabile de mediu (os.getenv(“MQTT_BROKER”)).
    • ESP32: Creați un fișier include/secrets.h cu credențialele și adăugați-l în .gitignore.
  3. Analiza vulnerabilității: Rulați bandit și cppcheck pe codul vostru. Documentați toate problemele găsite și remediați cele de nivel “High” și “Medium”.
ss/laboratoare/05.txt · Last modified: 2026/03/30 19:39 by ciprian.popescu0411
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0