Security Best Practices
This section discusses security considerations and best practices when using the Energy Manager IoT library.
Overview
Security is a critical aspect of any IoT system, especially one that manages device control and energy consumption. The Energy Manager IoT library provides several security features, but proper implementation is essential to ensure a secure deployment.
Connection Security
Using Secure MQTT Connections
Always use secure MQTT connections (mqtts://
) in production environments:
await manager.connect('mqtts://broker.example.com:8883', {
// TLS options
rejectUnauthorized: true, // Verify server certificate
ca: fs.readFileSync('ca-cert.pem') // Certificate Authority
});
TLS Certificate Verification
Properly validate server certificates to prevent man-in-the-middle attacks:
await manager.connect('mqtts://broker.example.com:8883', {
rejectUnauthorized: true, // Always set to true in production
ca: fs.readFileSync('ca-cert.pem'), // Custom CA if necessary
cert: fs.readFileSync('client-cert.pem'), // Client certificate
key: fs.readFileSync('client-key.pem') // Client private key
});
Private Key Security
Protect client private keys carefully and never include them in public code repositories.
Authentication
Username and Password Authentication
When username and password authentication is used, ensure strong passwords:
await manager.connect('mqtts://broker.example.com:8883', {
username: 'device-manager',
password: 'strong-unique-password'
});
Password Management
Use environment variables or secure credential management systems to store passwords:
Client Certificate Authentication
For higher security, use client certificate authentication:
await manager.connect('mqtts://broker.example.com:8883', {
cert: fs.readFileSync('client-cert.pem'),
key: fs.readFileSync('client-key.pem'),
rejectUnauthorized: true
});
Access Control
MQTT Topic Structure
Design your topic structure with security in mind:
- Use the topic prefix to create logical separation
- Limit subscription patterns to only what's needed
- Consider using topic hierarchies for access control
Broker-Level Access Control
Configure MQTT broker access control lists (ACLs) to restrict:
- Which clients can publish to which topics
- Which clients can subscribe to which topics
- Whether clients can publish retained messages
Command Security
Command Validation
Always validate commands before processing:
if (command.type === CommandType.SET_REPORTING) {
// Validate command parameters
if (!command.payload ||
typeof command.payload.interval !== 'number' ||
command.payload.interval < 10 ||
command.payload.interval > 3600) {
throw new Error('Invalid reporting interval');
}
// Process valid command
}
Command Authentication
Consider implementing a command authentication mechanism:
function verifyCommandAuthenticity(command) {
// Implement verification logic:
// - Check command signature
// - Verify timestamp is recent (prevent replay attacks)
// - Validate authorization for specific command
if (!isValidSignature(command) || isCommandExpired(command)) {
throw new SecurityError('Invalid or expired command');
}
}
Device Management Security
Device Registration
Implement secure device registration:
// Verify device identity before registration
function registerNewDevice(deviceId, deviceSecret) {
// Verify device identity with backend system
if (authenticateDevice(deviceId, deviceSecret)) {
manager.registerDevice(deviceId, deviceName, deviceType);
return true;
}
return false;
}
Group-Based Security
Use groups to implement logical security boundaries:
// Create groups with different security levels
manager.createGroup('admin-devices');
manager.createGroup('user-devices');
// Limit sensitive commands to admin devices
async function sendAdminCommand(command, payload) {
// Only send to admin devices
await manager.sendCommandToGroup('admin-devices', command, payload);
}
Network Security
Network Segmentation
Place the MQTT broker in an appropriate network segment:
- Use firewalls to restrict access to the broker
- Consider using VLANs or network segmentation
- Implement IP filtering if supported by your broker
Port Security
Use standard MQTT ports but restrict access:
- Port 1883: Standard MQTT (only use in secure networks)
- Port 8883: MQTT over TLS (recommended for external connections)
- Port 443: MQTT over WebSockets with TLS (for web clients)
Operational Security
Logging and Monitoring
Use the logging system to monitor for security events:
// Set up monitoring for security-related events
manager.on('error', (error) => {
if (error.type === ErrorType.AUTHENTICATION) {
securityLogger.warn('Authentication error detected', error);
alertSecurityTeam(error);
}
});
Secure Error Handling
Be careful about error information being exposed:
try {
await manager.sendCommand('device-id', CommandType.RESTART);
} catch (error) {
// Log full error details internally
logger.error('Command failed', error);
// Return limited information to clients
return {
success: false,
message: 'Command failed to execute',
errorCode: error instanceof EnergyManagerError ? error.code : 'UNKNOWN'
};
}
Implementation Checklist
Use this checklist to ensure secure implementation:
- Use TLS/SSL encryption (mqtts://) for all connections
- Implement strong authentication (certificates preferred)
- Configure proper access control at the broker level
- Use unique, random client IDs
- Validate all commands and payloads
- Implement proper error handling
- Use secure default configurations
- Enable logging for security auditing
- Keep the library and dependencies updated
- Protect credentials and certificates
Advanced Security Considerations
Penetration Testing
Regularly test your MQTT infrastructure for security vulnerabilities:
- Test MQTT broker configuration
- Verify TLS implementation
- Attempt unauthorized access
- Test command injection
Certificate Management
Implement proper certificate lifecycle management:
- Create a process for certificate rotation
- Monitor certificate expiration
- Implement certificate revocation
Rate Limiting
Consider implementing rate limiting for commands:
const commandTracking = new Map();
function checkCommandRateLimit(deviceId) {
const now = Date.now();
const history = commandTracking.get(deviceId) || [];
// Only keep commands from last 60 seconds
const recentCommands = history.filter(time => now - time < 60000);
// Update history
commandTracking.set(deviceId, [...recentCommands, now]);
// Check if too many commands
if (recentCommands.length >= 10) {
throw new EnergyManagerError(
'Rate limit exceeded',
ErrorType.RATE_LIMIT_EXCEEDED,
{ deviceId, commandCount: recentCommands.length },
ErrorSeverity.MEDIUM
);
}
}
// Use before sending commands
async function secureCommand(deviceId, command, payload) {
checkCommandRateLimit(deviceId);
await manager.sendCommand(deviceId, command, payload);
}