Practice Lab Guide

Project 7: IoT Security Hardening Assessment

Secure the Mosquitto broker using authenticated connections and audit your firmware and hardware interfaces.
Domain
IoT Cybersecurity
Difficulty
⭐⭐⭐⭐☆ (Advanced)
Course Module
IoT Security
Deliverables
Hardening Checklist, Secured Firmware
1. Threat Model & Authentication Interface

Local sandbox setups often bypass security features for convenience. However, exposing anonymous ports on your local network introduces significant vulnerabilities. The diagram below contrasts the unsecure setup with a hardened, password-authenticated environment. Enabling client authentication blocks rogue publishers from sending fake command payloads and prevents unauthorized subscribers from monitoring sensitive data channels.

UNSECURED MQTT CONTEXT Anonymous Client No login credentials Rogue Publisher Spoofs /relay payload MOSQUITTO BROKER allow_anonymous true HARDENED AUTHENTICATED CONTEXT ESP32 Client Node user: "iot_node_1" pass: "pbkdf2_sha..." Rogue Publisher CONNACK: Refused MOSQUITTO BROKER allow_anonymous false
2. Part 1: Step-by-Step Individual Security Configuration Commands

Follow these detailed steps to generate a password database inside your VM guest, restrict Mosquitto settings, and test connections.

STEP 1

Generate Mosquitto Password Database File

Open a terminal window inside the Ubuntu VM. Use the `mosquitto_passwd` tool to generate an encrypted password file.

ubuntu@iot-vm:~$ sudo mosquitto_passwd -c /etc/mosquitto/passwd user1
We run `mosquitto_passwd -c` as root to create a new password file at `/etc/mosquitto/passwd` containing a SHA-256 hashed entry for the user `user1`.
STEP 2

Input secure credential password

Type your secure password at the command prompt. Note that the characters will not display as you type for security.

Terminal prompts: Password: securePass123 Re-enter password: securePass123
We enter the password to let the tool hash the string, preventing credentials from being stored in plaintext on the filesystem.
STEP 3

Verify Password Encryption

Read the password file using `cat` to confirm that the password was hashed successfully.

ubuntu@iot-vm:~$ sudo cat /etc/mosquitto/passwd
We view the password file output to verify that the username is paired with a secure hash value rather than a plaintext string.
STEP 4

Restrict Broker Anonymous Connection Settings

Edit the configuration file in nano to disable anonymous access and link the password database.

ubuntu@iot-vm:~$ sudo nano /etc/mosquitto/mosquitto.conf
We open `/etc/mosquitto/mosquitto.conf` in the nano editor with root privileges to modify the access rules.
STEP 5

Update Configuration Settings in Nano

Scroll down to the bottom of the configuration file. Replace the old settings with the updated authentication rules.

Replace configuration text (use arrow keys, delete the old rule, paste the text below, press Ctrl+O, Enter, Ctrl+X): listener 1883 0.0.0.0 allow_anonymous false password_file /etc/mosquitto/passwd
We update the listener config, setting `allow_anonymous` to `false` and referencing the password file to enforce authentication for all incoming connections.
STEP 6

Restart the Mosquitto Service to Apply Settings

Reload the system service to apply the modified configuration rules.

ubuntu@iot-vm:~$ sudo systemctl restart mosquitto
We run `systemctl restart` to restart the Mosquitto daemon, forcing the process to read the new configuration rules.
STEP 7

Verify Unauthenticated Connections are Blocked

Attempt to subscribe to a topic without providing credentials. The broker should reject the connection.

ubuntu@iot-vm:~$ mosquitto_sub -h localhost -t "test/topic"
We attempt an anonymous subscription to verify that the broker correctly rejects the connection, returning an authorization error.
STEP 8

Verify Authenticated Connections are Accepted

Execute the subscription command again, this time providing your username (`-u`) and password (`-P`) flags.

ubuntu@iot-vm:~$ mosquitto_sub -h localhost -t "test/topic" -u "user1" -P "securePass123"
We run `mosquitto_sub` with the `-u` and `-P` flags to verify that authenticated clients are granted access to publish and subscribe to topics.
3. Firmware Auditing & Security Hardening Pipeline

Securing an IoT node requires hardening multiple layers of the system. The checklist pipeline below outlines the key validation stages to secure edge devices before deploying them to production.

1. Firmware Security Remove plaintext creds Enable encrypted flash Verify: Pass 2. Network Hardening Disable anonymous port Enforce authenticated QoS Verify: Pass 3. Interface Locking Disable unused JTAG pins Lock down physical UART Verify: Pass 4. Lifecycle Audit Implement signed OTA Rotate access tokens Hardening OK
4. Part 2: Hardened Firmware Code & Security Checklist Template

Below is the updated C++ code that includes username and password parameters in the MQTT connection loop, followed by a security audit checklist.

Asset 1: Hardened ESP32 MQTT Client Firmware (`secured_mqtt.ino`)

Line-by-Line Code Breakdown

// Practice Project 7: Hardened ESP32 MQTT Client Firmware #include <WiFi.h> #include <PubSubClient.h> const char* ssid = "YOUR_WIFI_SSID"; const char* password = "YOUR_WIFI_PASSWORD"; const char* mqtt_server = "192.168.1.120"; // Authenticated Credentials const char* mqtt_user = "user1"; const char* mqtt_pass = "securePass123"; WiFiClient espClient; PubSubClient client(espClient); void setup_wifi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } } void reconnect() { while (!client.connected()) { // Authenticated connection with LWT configured if (client.connect("ESP32_SecureNode", mqtt_user, mqtt_pass, "office/sensor1/status", 0, true, "offline")) { client.publish("office/sensor1/status", "online", true); client.subscribe("office/actuator/relay", 1); } else { delay(5000); } } } void setup() { setup_wifi(); client.setServer(mqtt_server, 1883); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); }

Asset 2: Hardening Checklist Template

# IoT Device Security Hardening Checklist ## 1. Network Layer Security * [ ] Disable anonymous access on all local brokers (`allow_anonymous false`). * [ ] Restrict connection endpoints to authorized local subnets or VPN interfaces. * [ ] Implement TLS/SSL encryption for MQTT traffic to prevent eavesdropping on port 8883. * [ ] Enforce client certificate validation (MQTTS) to prevent unauthorized devices from connecting. ## 2. Firmware Hardening * [ ] Remove plaintext Wi-Fi credentials and API keys from repository source files. * [ ] Store system credentials in secure, non-volatile storage partitions (e.g. ESP32 NVS). * [ ] Implement secure firmware updates using digital signatures to prevent rogue updates. * [ ] Enable flash encryption to protect compiled binaries from physical extraction. ## 3. Physical Security * [ ] Disable JTAG hardware debugging interfaces on deployed production devices. * [ ] Disable or password-protect serial console TX/RX interfaces on the board. * [ ] Enclose the hardware in tamper-resistant cases to prevent physical physical access.
5. Deliverables Summary

Created Artifacts

  • Secured firmware sketch: secured_mqtt.ino.
  • Modified configuration: /etc/mosquitto/mosquitto.conf.
  • Completed security hardening assessment report.

Verification Proof

  • A screenshot of the terminal displaying the hashed user entries in /etc/mosquitto/passwd.
  • A screenshot of the broker console log showing connection failures for anonymous clients, alongside successful authorization logs for the ESP32 node.
6. Closing Explanation: Why We Did This & What It Accomplishes

Architectural Intent & Operational Impact

Why We Did This

What This Accomplishes