Embedded Systems & Security: 5 Backend-Fallen, die du kennen musst
March 28, 2026Embedded Systems & Security: 5 Backend-Fallen, die du kennen musst
Warum Embedded Security auch deine Backend-Aufgabe ist
Fall 1: Ungesicherte Kommunikationskanäle
Python
# Beispiel: FastAPI Middleware zur Erzwingung von HTTPS (Grundlage)
# In einer echten Produktion wird dies oft vom Reverse Proxy (Nginx, Caddy) übernommen.
from fastapi import FastAPI, Request, HTTPException, status
app = FastAPI()
@app.middleware("http")
async def enforce_https(request: Request, call_next):
if request.url.scheme != "https":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Secure (HTTPS) connection required."
)
response = await call_next(request)
return response
@app.post("/device/data")
async def receive_device_data(data: dict):
# Hier findet die Verarbeitung der sicher empfangenen Daten statt
return {"status": "Daten sicher empfangen"}
# Für mTLS würde der Webserver (z.B. Nginx) die Client-Zertifikatsprüfung vor
# der Weiterleitung an FastAPI durchführen. FastAPI vertraut dann dem Proxy.
Fall 2: Mangelhaftes Device-Identity-Management
Python
# Beispiel: FastAPI mit JWT-Verifikation für Geräte-Identität
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from pydantic import BaseModel
import os
app = FastAPI()
SECRET_KEY = os.getenv("JWT_SECRET_KEY", "ein-sehr-sicherer-schluessel-aus-env")
ALGORITHM = "HS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token") # tokenUrl für Token-Ausgabe
class DeviceIdentity(BaseModel):
device_id: str
is_active: bool
async def get_current_device(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Ungültige oder fehlende Anmeldeinformationen",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
device_id: str = payload.get("sub")
if device_id is None:
raise credentials_exception
# Hier würde die Datenbankprüfung erfolgen, ob das Gerät aktiv ist
# und die Berechtigung besitzt. (z.B. select * from devices where id = :device_id and active = true)
if not device_id.startswith("dev-"): # Einfacher Platzhalter-Check
raise credentials_exception
return DeviceIdentity(device_id=device_id, is_active=True)
except JWTError:
raise credentials_exception
@app.post("/device/status")
async def update_device_status(device: DeviceIdentity = Depends(get_current_device), status_update: dict = None):
if not device.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Gerät ist nicht aktiv oder autorisiert")
# Verarbeitung des Status-Updates vom authentifizierten Gerät
return {"message": f"Status für Gerät {device.device_id} aktualisiert."}
Fall 3: Unzureichende API-Sicherung für Geräteinteraktion
Python
# Beispiel: FastAPI mit API Key Validierung und einfacher Ratenbegrenzung (konzeptionell)
from fastapi import FastAPI, Header, HTTPException, status
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
from collections import defaultdict
import time
app = FastAPI()
# In Produktion sollten API Keys sicher verwaltet werden (Secrets Manager)
DEVICE_API_KEYS = {
"device_xyz_key_1": "device_xyz",
"device_abc_key_2": "device_abc",
}
# Einfacher In-Memory Rate Limiter (nicht für Produktion geeignet, nur Demo!)
# Für Prod: Redis, etc.
request_counts = defaultdict(lambda: {'count': 0, 'timestamp': 0})
RATE_LIMIT_INTERVAL = 60 # Sekunden
RATE_LIMIT_MAX_REQUESTS = 100
class RateLimitMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
api_key = request.headers.get("X-API-Key")
if not api_key: # Unauthenticated requests bypass this specific limiter for simplicity
return await call_next(request)
now = time.time()
if now - request_counts[api_key]['timestamp'] > RATE_LIMIT_INTERVAL:
request_counts[api_key]['count'] = 0
request_counts[api_key]['timestamp'] = now
request_counts[api_key]['count'] += 1
if request_counts[api_key]['count'] > RATE_LIMIT_MAX_REQUESTS:
raise HTTPException(status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="Rate limit exceeded")
response = await call_next(request)
return response
app.add_middleware(RateLimitMiddleware)
async def verify_device_api_key(x_api_key: str = Header(..., alias="X-API-Key")):
if x_api_key not in DEVICE_API_KEYS:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Ungültiger API Key")
return DEVICE_API_KEYS[x_api_key]
@app.post("/device/telemetry")
async def receive_telemetry(
device_id: str = Depends(verify_device_api_key),
telemetry_data: dict = None
):
# Hier findet die eigentliche Verarbeitung der Telemetriedaten statt
# WICHTIG: telemetry_data MUSS hier noch validiert werden!
# Beispiel: if not isinstance(telemetry_data.get("temp"), (int, float)): ...
print(f"Telemetrie von {device_id} empfangen: {telemetry_data}")
return {"message": "Telemetrie empfangen", "device_id": device_id}
Fall 4: Fehlende Over-The-Air (OTA) Update-Security
Bash
# Konzeptionelles Bash-Beispiel für das Signieren von Firmware (Teil einer CI/CD-Pipeline)
# Dies geschieht im Backend, BEVOR das Update den Geräten zur Verfügung gestellt wird.
FIRMWARE_FILE="my_device_firmware_v1.2.bin"
SIGNATURE_FILE="${FIRMWARE_FILE}.sig"
PRIVATE_KEY="firmware_signing.key" # Diesen Schlüssel IMMER sicher aufbewahren!
echo "Generiere Hash der Firmware..."
sha256sum "${FIRMWARE_FILE}" > "${FIRMWARE_FILE}.sha256"
echo "Signiere den Firmware-Hash mit dem privaten Schlüssel..."
openssl dgst -sha256 -sign "${PRIVATE_KEY}" -out "${SIGNATURE_FILE}" "${FIRMWARE_FILE}.sha256"
echo "Firmware erfolgreich signiert. Nun "${FIRMWARE_FILE}" und "${SIGNATURE_FILE}" über das Backend bereitstellen."
# Auf der Geräteseite wird diese Signatur dann mit einem hinterlegten Public Key verifiziert.
Fall 5: Vernachlässigung der physischen Sicherheit und Tampering
Python
# Konzeptionelles Python-Beispiel für eine Anomalieerkennung im Backend (vereinfacht)
# Dies wäre Teil eines umfassenderen Monitoring- und Alarmsystems.
def check_device_telemetry_for_anomalies(device_id: str, telemetry: dict) -> bool:
# Beispiel: Gerät meldet eine unplausible Temperatur
if telemetry.get("temperature", 0) > 90.0 or telemetry.get("temperature", 0) < -20.0:
print(f"ALARM: Gerät {device_id} meldet extreme Temperatur: {telemetry.get('temperature')}°C")
return True
# Beispiel: Gerät meldet plötzlich ungewöhnlich hohe Leistungsaufnahme
if telemetry.get("power_consumption", 0) > 500:
print(f"ALARM: Gerät {device_id} meldet ungewöhnlich hohen Stromverbrauch: {telemetry.get('power_consumption')}W")
return True
# Weitere komplexe Anomalieerkennung basierend auf historischen Daten, Mustererkennung etc.
return False
@app.post("/device/events")
async def receive_device_events(
device_id: str = Depends(verify_device_api_key), # Verwendet die Authentifizierung aus Fall 3
event_data: dict = None
):
if check_device_telemetry_for_anomalies(device_id, event_data):
# Bei einer Anomalie können weitere Aktionen getriggert werden:
# - Alarm an Operatoren
# - Temporäre Deaktivierung des Geräts im Backend
# - Auslösen einer detaillierteren Untersuchung
pass
return {"message": "Ereignis empfangen", "device_id": device_id}