Table of Contents

Laborator 7: Securizarea aplicației web pentru gestionarea imaginilor

În cadrul acestui laborator ne vom axa pe implementarea securității Mutual TLS (mTLS) pentru comunicația MQTT din cadrul aplicației web.

Ce este mTLS?

Mutual TLS (mTLS) este un mecanism de autentificare bidirecțională în care:

  1. Serverul se autentifică față de client (TLS standard)
  2. Clientul se autentifică față de server (autentificare mutuală/bidirecțională)

Acest lucru asigură că:

Fișiere de modificat

Fișier Scop Modificări Necesare
broker/mosquitto.conf Configurare Broker Activarea listener-ului securizat pe portul 8883
docker-compose.yml Configurare Servicii Montarea secretelor și expunerea porturilor
server/main.go Backend Implementarea configurației TLS pentru clientul MQTT
scripts/send_image.py Script Python Configurarea contextului SSL/TLS

Cerințe preliminare

Pasul 1: Generarea certificatelor

1.1 Crearea Autorității de Certificare (CA)

mkdir -p secrets
cd secrets
 
# Generarea cheii private a CA
openssl genrsa -out ca.key 4096
 
# Generarea certificatului CA (valabil 10 ani)
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
    -subj "/C=RO/ST=Romania/L=Bucharest/O=SS-Web/OU=Security/CN=SS-Web-CA"

1.2 Crearea certificatului de server (pentru brokerul Mosquitto)

# Generarea cheii private a serverului
openssl genrsa -out server.key 2048
 
# Generarea cererii de semnare a certificatului de server (CSR)
openssl req -new -key server.key -out server.csr \
    -subj "/C=RO/ST=Romania/L=Bucharest/O=SS-Web/OU=Broker/CN=broker"
 
# Semnarea certificatului de server cu CA (valabil 1 an)
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out server.crt
 
# Curățare CSR
rm server.csr

1.3 Crearea certificatului de client (pentru API-ul Go și scripturile Python)

# Generarea cheii private a clientului
openssl genrsa -out web.key 2048
 
# Generarea cererii de semnare a certificatului de client (CSR)
openssl req -new -key web.key -out web.csr \
    -subj "/C=RO/ST=Romania/L=Bucharest/O=SS-Web/OU=WebClient/CN=web"
 
# Semnarea certificatului de client cu CA (valabil 1 an)
openssl x509 -req -days 365 -in web.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out web.crt
 
# Curățare CSR
rm web.csr

1.4 Verificarea certificatelor

# Verificarea certificatului CA
openssl x509 -in ca.crt -text -noout
 
# Verificarea certificatului de server
openssl verify -CAfile ca.crt server.crt
 
# Verificarea certificatului de client
openssl verify -CAfile ca.crt web.crt

Pasul 2: Configurarea brokerului Mosquitto

Editați broker/mosquitto.conf pentru a adăuga listener-ul securizat:

mosquitto.conf
# MQTT simplu (doar pentru dezvoltare - dezactivați în producție)
listener 1883
allow_anonymous true
 
# MQTT securizat cu mTLS
listener 8883
cafile /run/secrets/ca.crt
certfile /run/secrets/server.crt
keyfile /run/secrets/server.key
require_certificate true
use_subject_as_username true
allow_anonymous true
 
# Logare
log_type all
connection_messages true
log_timestamp true

Explicarea setărilor cheie:

Pasul 3: Configurarea Docker Compose

Actualizați docker-compose.yml pentru a monta secretele:

docker-compose.yml
services:
  go-api:
    # ... alte configurări ...
    secrets:
      - ca.crt
      - web.crt
      - web.key

  broker:
    # ... alte configurări ...
    ports:
      - "8883:8883"  # MQTT securizat
      - "1883:1883"  # MQTT simplu (dezactivați în producție)
    secrets:
      - ca.crt
      - server.crt
      - server.key

secrets:
  ca.crt:
    file: ./secrets/ca.crt
  web.crt:
    file: ./secrets/web.crt
  web.key:
    file: ./secrets/web.key
  server.crt:
    file: ./secrets/server.crt
  server.key:
    file: ./secrets/server.key

Pasul 4: Configurarea serverului Go

Actualizați server/main.go pentru a folosi TLS:

import (
    "crypto/tls"
    "crypto/x509"
    "os"
)
 
func NewTLSConfig() *tls.Config {
    // Încărcarea certificatului CA
    certpool := x509.NewCertPool()
    pemCerts, err := os.ReadFile("/run/secrets/ca.crt")
    if err != nil {
        panic(err)
    }
    certpool.AppendCertsFromPEM(pemCerts)
 
    // Încărcarea certificatului de client
    cert, err := tls.LoadX509KeyPair("/run/secrets/web.crt", "/run/secrets/web.key")
    if err != nil {
        panic(err)
    }
 
    return &tls.Config{
        RootCAs:            certpool,
        ClientCAs:          certpool,
        Certificates:       []tls.Certificate{cert},
        InsecureSkipVerify: false,
    }
}
 
func main() {
    // ... configurare MongoDB ...
 
    tlsconfig := NewTLSConfig()
 
    opts := mqtt.NewClientOptions()
    opts.AddBroker("ssl://broker:8883")
    opts.SetClientID("web").SetTLSConfig(tlsconfig)
 
    // ... restul codului ...
}

Pasul 5: Configurarea scripturilor Python

Actualizați scripturile Python pentru a folosi TLS:

import ssl
 
# Configurare
PORT = 8883  # Port securizat
 
# Căile către certificate
SECRETS_DIR = os.path.join(PROJECT_ROOT, "secrets")
CA_CRT = os.path.join(SECRETS_DIR, "ca.crt")
CLIENT_CRT = os.path.join(SECRETS_DIR, "web.crt")
CLIENT_KEY = os.path.join(SECRETS_DIR, "web.key")
 
# Crearea clientului MQTT
client = mqtt.Client(client_id="device-id")
 
# Configurarea TLS
client.tls_set(
    ca_certs=CA_CRT,
    certfile=CLIENT_CRT,
    keyfile=CLIENT_KEY,
    tls_version=ssl.PROTOCOL_TLSv1_2
)
# Omiterea verificării hostname-ului pentru testarea locală
client.tls_insecure_set(True)
 
# Conectare
client.connect(BROKER, PORT, 60)

Pasul 6: Testarea conexiunii

docker compose up -d
python3 scripts/send_image.py
docker logs broker

Depanare

Verificarea certificatului a eșuat

openssl x509 -in cert.crt -noout -dates

Conexiune refuzată pe portul 8883

docker logs broker

Verificarea hostname-ului a eșuat

Bune practici de securitate

  1. Nu comiteți niciodată certificate în git — Adăugați secrets/ în .gitignore
  2. Folosiți certificate cu durată scurtă de viață — Schimbați-le periodic
  3. Dezactivați MQTT simplu în producție — Eliminați listener-ul pe portul 1883
  4. Folosiți dimensiuni mari ale cheilor — 4096 biți pentru CA, minim 2048 biți pentru server/client
  5. Stocați cheile private în siguranță — Folosiți Docker secrets sau variabile de mediu

Lista de verificare a fișierelor

După implementare, directorul secrets/ ar trebui să conțină:

secrets/
├── ca.crt
├── ca.key
├── server.crt
├── server.key
├── web.crt
└── web.key