Day 5 of 5
⏱ ~60 minutes
IoT in 5 Days — Day 5

IoT Security

Unsecured IoT devices are the easiest entry point into networks. Today you'll learn to secure devices properly — from TLS through firmware updates.

OWASP IoT Top 10

The most common IoT vulnerabilities: 1. Weak passwords (hardcoded or default). 2. Insecure network services (unnecessary open ports). 3. Insecure ecosystem interfaces (API with no auth). 4. Lack of secure update mechanism. 5. Use of insecure or outdated components. 6. Insufficient privacy protection. 7. Insecure data transfer/storage (no TLS). 8. Lack of device management. 9. Insecure default settings. 10. Lack of physical hardening.

TLS for MQTT and HTTP

Enable TLS on Mosquitto: generate a CA and server certificate with openssl, configure listener 8883 with certfile/keyfile/cafile in mosquitto.conf. Client connects to port 8883 with CA certificate. For HTTPS on a web API, use Let's Encrypt (Certbot) for free certificates. On ESP32: use WiFiClientSecure and provide the server certificate fingerprint or CA cert.

OTA Firmware Updates

IoT devices must be updatable — security patches are ongoing. ESP32: Arduino OTA (ArduinoOTA.begin()) or ESP-IDF's OTA partition scheme (A/B partitions — write to B while running A, verify, then switch). Always verify firmware integrity with SHA-256 hash before flashing. Sign firmware with a private key; device verifies with embedded public key. Rollback if the new firmware fails to connect within 30 seconds.

python
# IoT security: TLS MQTT client + signed payload verification
# pip install paho-mqtt cryptography

import json, time, hmac, hashlib
import paho.mqtt.client as mqtt

# HMAC-based message authentication
# Device and server share a secret key
SECRET_KEY = b"your-32-byte-secret-key-here!!!!"

def sign_payload(payload_dict):
    # Add HMAC-SHA256 signature to payload
    body = json.dumps(payload_dict, sort_keys=True).encode()
    sig  = hmac.new(SECRET_KEY, body, hashlib.sha256).hexdigest()
    payload_dict['sig'] = sig
    return json.dumps(payload_dict)

def verify_payload(payload_str):
    # Verify HMAC signature, return payload or None if invalid
    try:
        d = json.loads(payload_str)
        received_sig = d.pop('sig', None)
        if not received_sig:
            return None
        body = json.dumps(d, sort_keys=True).encode()
        expected = hmac.new(SECRET_KEY, body, hashlib.sha256).hexdigest()
        if hmac.compare_digest(received_sig, expected):
            return d
        return None  # signature mismatch
    except:
        return None

# TLS MQTT client setup
def create_tls_client(client_id):
    client = mqtt.Client(client_id=client_id)
    # For local Mosquitto with self-signed cert:
    # client.tls_set(ca_certs="/etc/mosquitto/ca.crt",
    #                certfile="/etc/mosquitto/client.crt",
    #                keyfile="/etc/mosquitto/client.key")
    # client.tls_insecure_set(False)
    return client

# Test HMAC signing
payload = {"temp": 23.5, "hum": 55.2, "device": "esp32-01"}
signed = sign_payload(payload.copy())
print(f"Signed:   {signed}")

verified = verify_payload(signed)
print(f"Verified: {verified}")

# Tampered payload should fail
tampered = json.loads(signed)
tampered['temp'] = 99.9  # attacker changes temperature
tampered = json.dumps(tampered)
result = verify_payload(tampered)
print(f"Tampered: {result}")  # None = rejected
💡
HMAC payload signing protects against data tampering even if the network is compromised. An attacker intercepting MQTT messages cannot change temperature values without invalidating the signature — as long as the secret key is stored in secure flash on the device, not in the firmware binary.
📝 Day 5 Exercise
Harden Your IoT Deployment
  1. Enable TLS on your Mosquitto broker. Generate a self-signed CA and server cert with openssl. Verify that plain port 1883 is blocked (only 8883 works).
  2. Implement HMAC signing in the MQTT publisher and verification in the subscriber. Test that tampered messages are rejected.
  3. Run nmap against your IoT gateway: nmap -sV localhost. Close any ports that don't need to be open.
  4. Change all default credentials: Grafana admin password, InfluxDB admin token, MQTT username/password.
  5. Create a threat model: list all data flows in your IoT system. For each, note: is it encrypted? authenticated? what happens if compromised?

Day 5 Summary

  • OWASP IoT Top 10: weak passwords and no TLS are the most exploited vulnerabilities
  • TLS encrypts transport; HMAC signs payload content — use both for defense in depth
  • OTA must verify firmware integrity (SHA-256 hash) and authenticity (code signing) before flashing
  • Threat modeling: enumerate every data flow and ask 'what if this is compromised?'
Challenge

Implement certificate pinning for ESP32: instead of trusting any certificate signed by your CA, hardcode the exact server certificate fingerprint in the firmware. If the server cert changes (even from the same CA), the device rejects the connection. Research how to get the fingerprint: openssl x509 -fingerprint -sha256 -in server.crt. What are the trade-offs of pinning vs CA-trust?

Finished this lesson?