1454 IoT Security Hands-On Labs
1454.1 IoT Security Hands-On Labs
This chapter provides hands-on labs using Wokwi ESP32 simulators to practice implementing IoT security concepts including authentication, rate limiting, and threat detection.
1454.2 Learning Objectives
By completing these labs, you will be able to:
- Implement token-based authentication for IoT device access control
- Apply rate limiting to prevent brute force attacks
- Validate and sanitize commands to prevent injection attacks
- Build anomaly detection systems using statistical methods
- Log security events for monitoring and forensic analysis
1454.3 Lab 1: Build a Secure IoT Device with Authentication
This lab demonstrates core IoT security principles using an ESP32 microcontroller. You will implement authentication, rate limiting, and secure command validation.
1454.3.1 Lab Objectives
- Implement token-based authentication
- Apply rate limiting with exponential backoff
- Validate commands using whitelists
- Use visual feedback (LEDs) to indicate security states
- Log security events for audit trails
1454.3.2 Components
| Component | Purpose | Wokwi Element |
|---|---|---|
| ESP32 DevKit | Main controller with security logic | esp32:devkit-v1 |
| Green LED | Indicates authenticated/authorized state | led:green |
| Red LED | Indicates unauthorized access attempt | led:red |
| Yellow LED | Indicates rate limit warning/lockout | led:yellow |
| Push Button | Trigger authentication attempt | button |
| Resistors (3x 220 ohm) | Current limiting for LEDs | resistor |
1454.3.3 Interactive Wokwi Simulator
1454.3.4 Circuit Connections
ESP32 Pin Connections:
---------------------
GPIO 2 --> Green LED (+) --> 220 ohm Resistor --> GND
GPIO 4 --> Red LED (+) --> 220 ohm Resistor --> GND
GPIO 5 --> Yellow LED (+) --> 220 ohm Resistor --> GND
GPIO 15 --> Push Button --> GND (use internal pullup)
1454.3.5 Security Implementation Code
/*
* Secure IoT Device with Authentication
* Demonstrates: Token auth, rate limiting, command validation
*/
#include <Arduino.h>
// PIN DEFINITIONS
const int LED_AUTH_OK = 2; // Green LED - Authorized
const int LED_AUTH_FAIL = 4; // Red LED - Unauthorized
const int LED_RATE_LIMIT = 5; // Yellow LED - Rate limited
const int BUTTON_PIN = 15; // Authentication trigger
// SECURITY CONFIGURATION
const char* VALID_TOKENS[] = {
"IOT_SEC_TOKEN_2024_A1B2C3",
"IOT_SEC_TOKEN_2024_D4E5F6",
"ADMIN_MASTER_KEY_SECURED"
};
const int NUM_VALID_TOKENS = 3;
// Rate limiting configuration
const int MAX_FAILED_ATTEMPTS = 3;
const unsigned long LOCKOUT_DURATION = 30000; // 30 seconds
const unsigned long MIN_ATTEMPT_INTERVAL = 1000; // 1 second
// Valid commands whitelist
const char* VALID_COMMANDS[] = {
"STATUS", "LED_ON", "LED_OFF", "GET_TEMP", "RESET"
};
const int NUM_VALID_COMMANDS = 5;
// SECURITY STATE
struct SecurityState {
int failedAttempts;
unsigned long lockoutStartTime;
unsigned long lastAttemptTime;
bool isLocked;
bool isAuthenticated;
String currentToken;
String sessionId;
} secState;
void setup() {
Serial.begin(115200);
pinMode(LED_AUTH_OK, OUTPUT);
pinMode(LED_AUTH_FAIL, OUTPUT);
pinMode(LED_RATE_LIMIT, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Initialize security state
secState.failedAttempts = 0;
secState.isLocked = false;
secState.isAuthenticated = false;
Serial.println("Secure IoT Device Ready");
Serial.println("Commands: AUTH <token>, CMD <command>, LOGOUT");
}
void loop() {
// Handle button press for quick auth test
static bool lastButtonState = HIGH;
bool currentButtonState = digitalRead(BUTTON_PIN);
if (lastButtonState == HIGH && currentButtonState == LOW) {
authenticate("IOT_SEC_TOKEN_2024_A1B2C3");
}
lastButtonState = currentButtonState;
// Handle Serial commands
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
processCommand(input);
}
// Handle lockout expiration
if (secState.isLocked) {
unsigned long elapsed = millis() - secState.lockoutStartTime;
if (elapsed >= LOCKOUT_DURATION) {
secState.isLocked = false;
secState.failedAttempts = 0;
digitalWrite(LED_RATE_LIMIT, LOW);
Serial.println("[SECURITY] Lockout expired");
}
}
delay(50);
}
bool authenticate(const String& token) {
// Check if rate limited
if (secState.isLocked) {
Serial.println("[BLOCKED] Account locked");
return false;
}
// Rate limiting check
unsigned long now = millis();
if (now - secState.lastAttemptTime < MIN_ATTEMPT_INTERVAL) {
Serial.println("[RATE_LIMIT] Too fast!");
return false;
}
secState.lastAttemptTime = now;
// Validate token
bool tokenValid = false;
for (int i = 0; i < NUM_VALID_TOKENS; i++) {
if (token == VALID_TOKENS[i]) {
tokenValid = true;
break;
}
}
if (tokenValid) {
secState.isAuthenticated = true;
secState.failedAttempts = 0;
digitalWrite(LED_AUTH_OK, HIGH);
Serial.println("[SUCCESS] Authenticated");
return true;
} else {
secState.failedAttempts++;
Serial.print("[FAILED] Attempts: ");
Serial.println(secState.failedAttempts);
if (secState.failedAttempts >= MAX_FAILED_ATTEMPTS) {
secState.isLocked = true;
secState.lockoutStartTime = millis();
digitalWrite(LED_RATE_LIMIT, HIGH);
Serial.println("[LOCKED] 30 second lockout");
}
// Flash red LED
digitalWrite(LED_AUTH_FAIL, HIGH);
delay(200);
digitalWrite(LED_AUTH_FAIL, LOW);
return false;
}
}
void processCommand(const String& input) {
if (input.startsWith("AUTH ")) {
authenticate(input.substring(5));
}
else if (input.startsWith("CMD ")) {
if (!secState.isAuthenticated) {
Serial.println("[ERROR] Not authenticated");
return;
}
String cmd = input.substring(4);
executeCommand(cmd);
}
else if (input == "LOGOUT") {
secState.isAuthenticated = false;
digitalWrite(LED_AUTH_OK, LOW);
Serial.println("[AUTH] Logged out");
}
}
void executeCommand(const String& command) {
// Whitelist validation
bool valid = false;
for (int i = 0; i < NUM_VALID_COMMANDS; i++) {
if (command == VALID_COMMANDS[i]) {
valid = true;
break;
}
}
if (!valid) {
Serial.println("[REJECTED] Invalid command");
return;
}
// Execute validated command
if (command == "STATUS") {
Serial.println("Device: ONLINE");
}
else if (command == "LED_ON") {
digitalWrite(LED_AUTH_OK, HIGH);
}
else if (command == "LED_OFF") {
digitalWrite(LED_AUTH_OK, LOW);
}
else if (command == "GET_TEMP") {
float temp = 22.5 + (random(0, 50) / 10.0);
Serial.print("Temperature: ");
Serial.println(temp);
}
}1454.3.6 Lab Steps
- Build the circuit in Wokwi following the pin connections
- Copy the code into the Wokwi editor
- Start simulation and open the Serial Monitor
- Test authentication:
- Try:
AUTH wrong_password(should fail) - Try:
AUTH IOT_SEC_TOKEN_2024_A1B2C3(should succeed)
- Try:
- Test rate limiting:
- Enter 3 wrong passwords quickly
- Observe 30-second lockout (yellow LED)
- Test command validation:
- After authenticating, try:
CMD STATUS - Try:
CMD DROP_TABLE(should be rejected)
- After authenticating, try:
1454.3.7 Security Concepts Demonstrated
| Concept | Implementation | Real-World Application |
|---|---|---|
| Token Authentication | Whitelist of valid tokens | API keys, JWT tokens |
| Rate Limiting | Max attempts with lockout | Brute force prevention |
| Command Whitelisting | Only approved commands execute | Injection attack prevention |
| Visual Feedback | LED indicators for states | Security dashboards |
| Audit Logging | Serial output of all events | SIEM systems |
1454.4 Lab 2: Build a Secure IoT Device with Threat Detection
This lab builds on the authentication lab to add anomaly detection and intrusion prevention capabilities.
1454.4.1 Lab Objectives
- Implement statistical anomaly detection
- Build DoS protection with rate limiting
- Create pattern-based attack detection
- Implement multi-level threat response
- Practice security event correlation
1454.4.2 Threat Detection Features
- Anomaly Detection: Z-score analysis to detect unusual sensor readings
- DoS Protection: Request rate limiting with blocking
- Port Scan Detection: Correlation of multiple connection attempts
- Brute Force Detection: Authentication failure pattern recognition
- Threat Levels: Graduated response based on attack severity
1454.4.3 Simplified Detection Code
/*
* IoT Threat Detection System
* Demonstrates: Anomaly detection, DoS protection, attack correlation
*/
#include <Arduino.h>
const int LED_NORMAL = 2; // Green - Normal operations
const int LED_WARNING = 4; // Yellow - Elevated threat
const int LED_CRITICAL = 5; // Red - Critical threat
// Baseline for anomaly detection
float sensorBaseline = 25.0;
float sensorStdDev = 2.0;
// Rate limiting
const int MAX_REQUESTS_PER_SECOND = 10;
int requestCount = 0;
unsigned long lastSecond = 0;
// Threat level
enum ThreatLevel { NORMAL, LOW, MEDIUM, HIGH, CRITICAL };
ThreatLevel currentThreat = NORMAL;
void setup() {
Serial.begin(115200);
pinMode(LED_NORMAL, OUTPUT);
pinMode(LED_WARNING, OUTPUT);
pinMode(LED_CRITICAL, OUTPUT);
digitalWrite(LED_NORMAL, HIGH); // Normal state
Serial.println("Threat Detection System Active");
Serial.println("Commands: SENSOR <value>, DOS, SCAN, STATUS");
}
void loop() {
// Reset rate limiter each second
if (millis() - lastSecond >= 1000) {
requestCount = 0;
lastSecond = millis();
}
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
processInput(input);
}
updateThreatIndicators();
delay(50);
}
void processInput(const String& input) {
// Rate limit check
requestCount++;
if (requestCount > MAX_REQUESTS_PER_SECOND) {
Serial.println("[DOS_BLOCKED] Rate limit exceeded");
raiseThreatLevel(HIGH);
return;
}
if (input.startsWith("SENSOR ")) {
float value = input.substring(7).toFloat();
checkAnomaly(value);
}
else if (input == "DOS") {
Serial.println("[ATTACK] DoS simulation");
raiseThreatLevel(HIGH);
}
else if (input == "SCAN") {
Serial.println("[ATTACK] Port scan detected");
raiseThreatLevel(MEDIUM);
}
else if (input == "STATUS") {
printStatus();
}
}
void checkAnomaly(float value) {
// Z-score calculation
float zScore = abs(value - sensorBaseline) / sensorStdDev;
Serial.print("Value: ");
Serial.print(value);
Serial.print(" | Z-score: ");
Serial.println(zScore);
if (zScore > 3.0) {
Serial.println("[ANOMALY] Suspicious reading detected");
raiseThreatLevel(MEDIUM);
} else if (zScore > 2.0) {
Serial.println("[WARNING] Elevated reading");
raiseThreatLevel(LOW);
} else {
Serial.println("[NORMAL] Reading within baseline");
}
}
void raiseThreatLevel(ThreatLevel level) {
if (level > currentThreat) {
currentThreat = level;
Serial.print("[THREAT] Level raised to: ");
Serial.println(level);
}
}
void updateThreatIndicators() {
digitalWrite(LED_NORMAL, currentThreat == NORMAL);
digitalWrite(LED_WARNING, currentThreat >= LOW && currentThreat < HIGH);
digitalWrite(LED_CRITICAL, currentThreat >= HIGH);
}
void printStatus() {
Serial.println("=== SYSTEM STATUS ===");
Serial.print("Threat Level: ");
Serial.println(currentThreat);
Serial.print("Requests this second: ");
Serial.println(requestCount);
Serial.print("Baseline: ");
Serial.println(sensorBaseline);
}1454.4.4 Testing the Threat Detection Lab
- Normal operation:
SENSOR 24.5(within baseline) - Anomaly detection:
SENSOR 100.0(high Z-score, triggers warning) - DoS simulation: Enter
DOSto simulate attack - Rate limiting: Enter many commands quickly to trigger rate limit
1454.5 Lab Challenges
Modify the authentication system so tokens expire after 5 minutes of inactivity. Implement automatic logout.
Add a second factor: after token authentication, require the user to press the button within 10 seconds to complete login.
Implement simple XOR encryption for commands sent over serial. The key should be established during authentication.
Add a βtrapβ token that, when used, immediately locks the device and logs the attempt with high severity.
Detect attack chains: scan followed by brute force followed by anomalous commands should trigger critical alert.
1454.6 From Lab to Production
| Lab Implementation | Production Equivalent |
|---|---|
| Serial commands | MQTT/CoAP over TLS |
| Hardcoded tokens | Certificate-based auth, JWT |
| LED indicators | Security dashboards, SIEM |
| Serial logging | Centralized log aggregation |
| Simple rate limiting | Distributed rate limiting (Redis) |
| Z-score anomaly | ML models (Isolation Forest) |
1454.7 Summary
These labs demonstrated practical IoT security:
- Authentication: Token-based access control with secure validation
- Rate Limiting: Preventing brute force with lockout mechanisms
- Command Validation: Whitelist-based input sanitization
- Anomaly Detection: Statistical methods to detect unusual behavior
- Threat Response: Multi-level alerts based on attack severity
1454.8 Whatβs Next
The final chapter provides Visual Resources including AI-generated diagrams for encryption, attack scenarios, and security architectures.
Continue to Visual Resources β