🔒 Sicherheits-Konzept: Mittlere Findings Behebung¶
Datum: 24. Februar 2026
Scope: Behebung aller MITTEL-Priority Findings (#8-#15) aus dem Security Audit Report
Status: Konzeptphase - Vor Implementierung
📋 Übersicht¶
Dieses Dokument beschreibt die geplanten Maßnahmen zur Behebung der mittleren Sicherheitsrisiken. Die Implementierung erfolgt in 3 Phasen mit klaren Prioritäten.
Findings im Scope¶
- ✅ #7: SharedPreferences Encryption (HOCH) - BEREITS BEHOBEN
- 🔧 #8: Certificate Pinning (MITTEL)
- 🔧 #9: ERP Firestore Rules härten (MITTEL)
- 🔧 #10: JSON.parse Error Handling (MITTEL)
- 🔧 #11: Content-Type Validierung bei Uploads (MITTEL)
- 🔧 #12: CORS-Konfiguration Review (MITTEL)
- 🔧 #13: SQL Injection Protection bei Connector Templates (MITTEL)
- 🔧 #14: Session Management (MITTEL)
- 🔧 #15: Error Handling bei Firestore Queries (MITTEL)
🎯 PHASE 1: Backend Security (Cloud Functions & Firestore)¶
Zeitaufwand: 3-4 Stunden
Priorität: HOCH (serverseitige Sicherheit)
1.1 JSON.parse Error Handling (#10)¶
Problem:
// UNSICHER - Kann bei korrupten Daten crashen
credentials = JSON.parse(version.payload.data.toString('utf8'));
Betroffene Dateien:
- functions/src/jobs/management/updateJob.js (Zeile 96)
- functions/src/jobs/executor/executeJobHttp.js (Zeile 113)
- functions/src/jobs/management/getJobCredentials.js (Zeile 60)
- functions/src/jobs/executor/executeJob.js (Zeile 76)
- functions/src/jobs/management/testJob.js (Zeile 44)
- functions/src/utils/connector_utils.js (Zeile 19)
- functions/src/connectors/connector_management.js (Zeilen 233, 367, 444)
Lösung:
-
Utility-Funktion erstellen:
functions/src/utils/json_utils.jsconst functions = require('firebase-functions'); /** * Sicheres JSON Parsing mit Error Handling * @param {string} jsonString - Der zu parsende JSON String * @param {string} context - Kontext für Fehlermeldung (z.B. "credentials") * @returns {Object} Geparstes Object * @throws {functions.https.HttpsError} Bei Parsing-Fehler */ function safeJsonParse(jsonString, context = 'data') { try { // Validierung: String muss vorhanden sein if (!jsonString || typeof jsonString !== 'string') { throw new Error(`Invalid input: Expected string, got ${typeof jsonString}`); } // Validierung: String darf nicht leer sein if (jsonString.trim().length === 0) { throw new Error('Empty JSON string'); } const parsed = JSON.parse(jsonString); // Validierung: Ergebnis muss ein Object sein if (!parsed || typeof parsed !== 'object') { throw new Error(`Invalid JSON structure: Expected object, got ${typeof parsed}`); } return parsed; } catch (error) { console.error(`[SECURITY] Failed to parse ${context}:`, error.message); throw new functions.https.HttpsError( 'invalid-argument', `Invalid ${context} format: ${error.message}` ); } } /** * Sicheres Parsen von Secret Manager Payloads * @param {Object} version - Secret Manager Version Object * @param {string} secretName - Name des Secrets für Logging * @returns {Object} Credentials Object */ function parseSecretPayload(version, secretName = 'secret') { if (!version || !version.payload || !version.payload.data) { throw new functions.https.HttpsError( 'internal', `Secret ${secretName} has invalid structure` ); } const jsonString = version.payload.data.toString('utf8'); return safeJsonParse(jsonString, `secret:${secretName}`); } module.exports = { safeJsonParse, parseSecretPayload }; -
Alle betroffenen Dateien aktualisieren
Erwartete Verbesserung: - ✅ Keine unbehandelten Exceptions bei korrupten Secrets - ✅ Klare Fehlermeldungen für Debugging - ✅ Security Logging bei Parse-Fehlern - ✅ Konsistentes Error Handling über alle Functions
1.2 ERP Firestore Rules härten (#9)¶
Problem:
Fallback-Regel ist zu permissiv - neue Collections haben automatisch vollen Zugriff.Betroffene Datei:
- firestore.rules (Zeilen 330-337)
Lösung:
-
Fallback-Regel ändern (Secure by Default):
// ============================================================================ // FALLBACK: Explizit ALLES verbieten (Secure by Default) // ============================================================================ // Jede Collection muss explizit freigegeben werden. // Dies verhindert versehentliche Datenlecks bei neuen Collections. match /{document=**} { allow read, write: if false; } -
Fehlende Collections explizit freigeben
Analyse der aktuellen Rules: - ✅ system_settings: Explizit definiert (read: auth, write: admin) - ✅ users: Explizit definiert (komplex) - ✅ customers: Explizit definiert (permissions-basiert) - ✅ articles: Explizit definiert (permissions-basiert) - ✅ orders: Explizit definiert (permissions-basiert) - ✅ customerUsers: Explizit definiert (admin only) - ✅ articleCategories: Explizit definiert - ✅ customerCategorys: Explizit definiert - ✅ notifications: Explizit definiert - ✅ notificationGroups: Explizit definiert - ⚠️ Potentiell fehlend: - jobs & jobExecutions (via Cloud Functions) - statistics (via Cloud Functions) - connectorSettings (via Cloud Functions) - deviceTokens (Push Notifications) - auditLogs (falls vorhanden)
- Neue explizite Regeln hinzufügen:
// ============================================================================ // JOBS - Nur Cloud Functions haben Zugriff // ============================================================================ // Jobs werden ausschließlich von Cloud Functions verwaltet. // Client-Apps haben keinen direkten Zugriff. match /jobs/{jobId} { allow read: if isAdmin(); // Admins können Jobs einsehen allow write: if false; // Nur Cloud Functions (Admin SDK) match /jobExecutions/{executionId} { allow read: if isAdmin(); allow write: if false; } } // ============================================================================ // STATISTICS - Nur Lese-Zugriff für authentifizierte User // ============================================================================ match /statistics/{statisticId} { allow read: if isAuthenticated(); allow write: if false; // Nur Cloud Functions } match /statistics/{statisticId}/{subcollection=**} { allow read: if isAuthenticated(); allow write: if false; } // ============================================================================ // CONNECTOR SETTINGS - Nur Admin-Zugriff // ============================================================================ // Connector-Credentials liegen in Secret Manager, nicht in Firestore match /connectorSettings/{settingId} { allow read: if isAdmin(); allow write: if isAdmin(); // Nur für Connector-Konfiguration, NICHT Credentials } // ============================================================================ // DEVICE TOKENS - Für Push Notifications // ============================================================================ match /deviceTokens/{tokenId} { allow read: if isAuthenticated(); // User kann eigenes Device Token registrieren allow create, update: if isAuthenticated() && request.auth.uid == request.resource.data.userId; allow delete: if isAuthenticated() && request.auth.uid == resource.data.userId; } // ============================================================================ // AUDIT LOGS - Nur Lesen für SuperAdmin // ============================================================================ match /auditLogs/{logId} { allow read: if isSuperAdmin(); allow write: if false; // Nur Cloud Functions }
Implementierungsschritte:
1. Backup der aktuellen firestore.rules erstellen
2. Fallback-Regel auf if false ändern
3. Neue explizite Regeln hinzufügen
4. Deployment testen (zuerst in Dev-Umgebung!)
5. Mit firebase emulators:start lokal testen
6. Production Deployment
Erwartete Verbesserung: - ✅ Secure by Default - neue Collections sind standardmäßig geschützt - ✅ Keine versehentlichen Datenlecks - ✅ Explizite Dokumentation aller zugänglichen Collections - ✅ Auditable Security Rules
1.3 CORS-Konfiguration Review (#12)¶
Betroffene Dateien:
- cors.json (Root-Level)
- apps/erp_system/cors.json
- apps/shop_system/cors.json
- apps/shop_system/cors-config.json
Aktuelle Konfiguration (Root):
{
"origin": ["https://es-dev-2-d4e1a.web.app", "https://es-dev-2-d4e1a.firebaseapp.com", "http://localhost:8080"],
"method": ["GET"],
"responseHeader": ["Content-Type"],
"maxAgeSeconds": 3600
}
Probleme: - ⚠️ Nur GET erlaubt - was ist mit POST für Uploads? - ⚠️ Development URLs in Production Config? - ⚠️ Keine Unterscheidung zwischen Dev/Staging/Prod
Lösung:
- Umgebungs-spezifische CORS Configs:
cors.dev.json:
[
{
"origin": [
"http://localhost:8080",
"http://localhost:5000",
"https://es-dev-2-d4e1a.web.app",
"https://es-dev-2-d4e1a.firebaseapp.com"
],
"method": ["GET", "HEAD", "PUT", "POST", "DELETE"],
"responseHeader": ["Content-Type", "Authorization"],
"maxAgeSeconds": 3600
}
]
cors.prod.json:
[
{
"origin": [
"https://your-production-domain.com"
],
"method": ["GET", "HEAD", "PUT", "POST"],
"responseHeader": ["Content-Type", "Authorization"],
"maxAgeSeconds": 86400
}
]
- Deployment Script anpassen:
Erwartete Verbesserung: - ✅ Produktions-Umgebung akzeptiert nur Production-Domains - ✅ Minimal notwendige HTTP-Methoden pro Umgebung - ✅ Keine Wildcard-Origins - ✅ Getrennte Configs für Dev/Staging/Prod
🎯 PHASE 2: Client Security (Flutter Apps)¶
Zeitaufwand: 4-5 Stunden
Priorität: MITTEL
2.1 Certificate Pinning (#8)¶
Problem:
Kein Certificate Pinning - anfällig für MITM-Angriffe.Betroffene Dateien:
- apps/shop_system/lib/services/mobile/document_download_service.dart
Lösung:
Option A: SSL Certificate Pinning mit dio (Empfohlen)
-
Certificate Hash ermitteln:
-
Pinning Service erstellen:
lib/services/ssl_pinning_service.dartimport 'dart:io'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; class SSLPinningConfig { // 🔒 SECURITY: Firebase Storage Certificate Fingerprints // Diese Hashes müssen aktualisiert werden wenn Firebase Certificates erneuert (ca. alle 1-2 Jahre) // Letztes Update: 24. Februar 2026 static const List<String> _firebaseStoragePins = [ // Primary Certificate 'AABBCCDD...', // SHA-256 Fingerprint // Fallback Certificate (für graceful rotation) 'EEFFGGHH...', // SHA-256 Fingerprint ]; static Dio createSecureDio() { final dio = Dio(); // Custom HttpClient mit Certificate Pinning (dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () { final client = HttpClient(); client.badCertificateCallback = (cert, host, port) { // SECURITY: Nur für Firebase Storage Hosts pinnen if (!host.contains('firebasestorage.googleapis.com') && !host.contains('storage.googleapis.com')) { // Für andere Hosts: Standard SSL Validierung return false; } // Certificate Fingerprint prüfen final certSHA256 = cert.sha256.toString(); if (_firebaseStoragePins.contains(certSHA256)) { return true; // Certificate ist gepinnt ✅ } // SECURITY ALERT: Certificate nicht gepinnt! print('⚠️ [SECURITY] SSL Certificate Pinning fehlgeschlagen!'); print('Host: $host'); print('Expected: ${_firebaseStoragePins.join(', ')}'); print('Got: $certSHA256'); return false; // Verbindung ablehnen }; return client; }; return dio; } } -
Document Download Service aktualisieren:
Option B: Ohne Pinning, aber mit strikter SSL Validierung
import 'dart:io';
class SSLConfig {
static Dio createSecureDio() {
final dio = Dio();
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
final client = HttpClient();
// Strikte SSL Validierung (kein badCertificateCallback)
// Nur valide, vertrauenswürdige Zertifikate werden akzeptiert
client.badCertificateCallback = null;
return client;
};
return dio;
}
}
Empfehlung: - Production: Option A (Certificate Pinning für maximale Sicherheit) - Development: Option B (vereinfacht Testing mit lokalen Zertifikaten)
Certificate Rotation Prozess: 1. Monitoring: Automatische Alerts 60 Tage vor Certificate-Ablauf 2. Update: Neue Certificate Hashes in App-Update einbauen 3. Overlap: Beide Hashes (alt & neu) für 30 Tage parallel akzeptieren 4. Cleanup: Alte Hashes nach erfolgreicher User-Migration entfernen
Erwartete Verbesserung: - ✅ Schutz vor MITM-Angriffen auf Firebase Storage - ✅ Garantie der Server-Authentizität - ✅ Compliance mit Security Best Practices
2.2 Session Management (#14)¶
Problem: Keine sichtbare Session Timeout Konfiguration oder Token Refresh Logik.
Analyse benötigt: - Wo wird Firebase Auth genutzt? - Gibt es einen AuthService? - Wie wird Token Expiration gehandhabt?
Lösung:
-
Auth Service erweitern (falls vorhanden):
lib/services/auth_service.dartimport 'package:firebase_auth/firebase_auth.dart'; class AuthService { final FirebaseAuth _auth = FirebaseAuth.instance; // 🔒 SECURITY: Session Timeout Configuration static const Duration _sessionTimeout = Duration(hours: 12); static const Duration _tokenRefreshThreshold = Duration(minutes: 5); /// Prüft ob das Token bald abläuft und erneuert es proaktiv Future<void> refreshTokenIfNeeded() async { final user = _auth.currentUser; if (user == null) return; try { final token = await user.getIdTokenResult(); final expirationTime = token.expirationTime; if (expirationTime == null) { print('⚠️ [AUTH] Token expiration time unknown'); return; } final timeUntilExpiration = expirationTime.difference(DateTime.now()); // Token läuft in weniger als 5 Minuten ab? → Refresh if (timeUntilExpiration < _tokenRefreshThreshold) { print('🔄 [AUTH] Refreshing token (expires in ${timeUntilExpiration.inMinutes}min)'); await user.getIdToken(true); // Force refresh print('✅ [AUTH] Token refreshed successfully'); } } catch (e) { print('❌ [AUTH] Token refresh failed: $e'); // Bei kritischen Fehlern: User ausloggen if (e.toString().contains('network-request-failed')) { // Netzwerkfehler: Nicht ausloggen } else { // Andere Fehler: Sicherheitshalber ausloggen await signOut(); } } } /// Prüft ob die Session abgelaufen ist (inaktiv zu lange) Future<bool> isSessionValid() async { final user = _auth.currentUser; if (user == null) return false; final metadata = user.metadata; final lastSignIn = metadata.lastSignInTime; if (lastSignIn == null) return false; final sessionAge = DateTime.now().difference(lastSignIn); if (sessionAge > _sessionTimeout) { print('⚠️ [AUTH] Session expired (${sessionAge.inHours}h)'); await signOut(); return false; } return true; } Future<void> signOut() async { await _auth.signOut(); } } -
App Lifecycle Hook: In
main.dartoder zentralem App-Widgetclass _MyAppState extends State<MyApp> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); // Initial Token Refresh _refreshTokenPeriodically(); } void _refreshTokenPeriodically() { Timer.periodic(Duration(minutes: 4), (timer) { final authService = getIt<AuthService>(); authService.refreshTokenIfNeeded(); }); } @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { // App kommt in Vordergrund: Session validieren final authService = getIt<AuthService>(); authService.isSessionValid(); authService.refreshTokenIfNeeded(); } } }
Erwartete Verbesserung: - ✅ Proaktive Token-Erneuerung verhindert Ablauf während Nutzung - ✅ Session Timeout erhöht Security bei Device-Verlust - ✅ Automatisches Logout bei langer Inaktivität - ✅ Bessere User Experience (keine plötzlichen Auth-Fehler)
2.3 Error Handling bei Firestore Queries (#15)¶
Problem: Viele Firestore-Queries haben kein explizites Timeout oder Error Handling.
Aktueller Stand:
✅ extensions/firestore_extensions.dart hat bereits Timeout implementiert
Lösung:
-
Prüfen ob Extensions genutzt werden:
-
Falls nicht konsequent genutzt: Migration
Erstelle Linter-Regel oder Code-Search um unsichere Queries zu finden:
// UNSICHER - ohne Timeout
final doc = await FirebaseFirestore.instance.collection('test').doc('id').get();
// SICHER - mit Timeout
final doc = await FirebaseFirestore.instance.collection('test').doc('id').getSafe();
- Globale Firestore Konfiguration:
// lib/config/firestore_config.dart import 'package:cloud_firestore/cloud_firestore.dart'; class FirestoreConfig { static void initialize() { FirebaseFirestore.instance.settings = Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, // Timeout auf Firestore-Verbindungs-Ebene (experimentell) ); } }
Implementierungsschritte:
1. Audit aller Firestore-Queries (automatisiert via grep)
2. Migration zu getSafe() Extension
3. Code Review Guideline: Nur noch getSafe() nutzen
4. Optional: Custom Lint Rule erstellen
Erwartete Verbesserung: - ✅ Keine hängenden Queries bei Netzwerkproblemen - ✅ Konsistentes Error Handling - ✅ Bessere User Experience (Loading States enden)
🎯 PHASE 3: Connector & Template Security¶
Zeitaufwand: 2-3 Stunden
Priorität: NIEDRIG (betrifft nur interne Connector-Entwicklung)
3.1 SQL Injection Protection bei Connector Templates (#13)¶
Betroffene Dateien:
- functions/src/connectors/templates/rest_api_template.js
- Alle Custom Connector Implementierungen
Problem: Wenn Connectoren SQL-Datenbanken anbinden, fehlt dokumentierte Best Practice für Prepared Statements.
Lösung:
-
SQL Connector Template erstellen:
functions/src/connectors/templates/sql_connector_template.js/** * SQL Connector Template mit Security Best Practices * * SECURITY REQUIREMENTS: * 1. IMMER Prepared Statements nutzen (NIEMALS String Concatenation) * 2. Input Validation für alle Parameter * 3. Least Privilege: Database User hat nur SELECT Rechte * 4. Connection Pooling mit Timeouts * 5. Error Messages dürfen keine DB-Struktur leaken */ const mysql = require('mysql2/promise'); class SQLConnector { constructor(credentials) { this.pool = mysql.createPool({ host: credentials.host, user: credentials.user, password: credentials.password, database: credentials.database, waitForConnections: true, connectionLimit: 10, queueLimit: 0, connectTimeout: 10000, // SECURITY: SSL für Produktions-DBs erzwingen ssl: credentials.ssl_enabled ? { rejectUnauthorized: true } : false }); } /** * Sichere Query-Ausführung mit Prepared Statements * @param {string} query - SQL Query mit ? Platzhaltern * @param {Array} params - Parameter für Query * @returns {Promise<Array>} Query Ergebnisse */ async executeQuery(query, params = []) { try { // SECURITY: Validiere Query-Typ (nur SELECT erlaubt für Datenabruf) const queryType = query.trim().toUpperCase().split(' ')[0]; if (!['SELECT'].includes(queryType)) { throw new Error(`Query type ${queryType} not allowed for data connector`); } // SECURITY: Prepared Statement schützt vor SQL Injection const [rows] = await this.pool.execute(query, params); return rows; } catch (error) { // SECURITY: Sanitize error message (keine DB-Internals leaken) console.error('[SQL Connector] Query failed:', error.message); throw new Error('Database query failed. Check connector configuration.'); } } /** * EXAMPLE: Customer Sync */ async syncCustomers(lastSyncTimestamp) { // 🔒 RICHTIG: Prepared Statement const query = ` SELECT id, name, email, updated_at FROM customers WHERE updated_at > ? ORDER BY updated_at ASC LIMIT 1000 `; const customers = await this.executeQuery(query, [lastSyncTimestamp]); return customers; } /** * ❌ FALSCH - NIEMALS SO MACHEN! */ async syncCustomersUnsafe(lastSyncTimestamp) { // SQL INJECTION MÖGLICH! const query = `SELECT * FROM customers WHERE updated_at > '${lastSyncTimestamp}'`; // Attacker könnte lastSyncTimestamp = "'; DROP TABLE customers; --" setzen } async close() { await this.pool.end(); } } module.exports = SQLConnector; -
Security Checklist für Connector-Entwickler:
functions/src/connectors/SECURITY_CHECKLIST.md# Connector Security Checklist Vor Deployment eines neuen Connectors ALLE Punkte prüfen: ## SQL-basierte Connectoren - [ ] Prepared Statements für ALLE Queries - [ ] Kein String Concatenation für SQL Queries - [ ] Database User hat nur SELECT Rechte (kein INSERT/UPDATE/DELETE) - [ ] SSL/TLS Verbindung zur Datenbank - [ ] Connection Timeout konfiguriert (max 10 Sekunden) - [ ] Error Messages leaken keine DB-Struktur - [ ] Query LIMIT implementiert (max 10.000 Datensätze) ## API-basierte Connectoren - [ ] API Key/Token werden in Secret Manager gespeichert - [ ] HTTPS für alle API Calls (kein HTTP) - [ ] Request Timeout konfiguriert (max 30 Sekunden) - [ ] Rate Limiting beachtet - [ ] Input Validation für alle Parameter - [ ] API Fehler werden nicht 1:1 an Client weitergegeben ## Allgemein - [ ] Credentials niemals im Code (nur Secret Manager) - [ ] Logging ohne sensible Daten (PII) - [ ] Error Handling implementiert - [ ] Unit Tests für Connector geschrieben
Erwartete Verbesserung: - ✅ Verhindert SQL Injection in Custom Connectoren - ✅ Dokumentierte Best Practices für Entwickler - ✅ Template als Startpunkt für neue Connectoren
3.2 Content-Type Validierung bei Uploads (#11)¶
Betroffene Datei:
- storage.rules
Problem:
Storage Rules validieren nur bei article_documents die Dateigröße, nicht aber Content-Types konsistent.
Lösung:
Siehe Finding #2 aus dem Security Audit Report - bereits dokumentiert.
Kurzversion:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Helper: Prüft ob customerId zum User gehört (via Firestore)
function hasCustomerAccess(customerId) {
return request.auth != null &&
firestore.get(/databases/(default)/documents/customerUsers/$(request.auth.uid)).data.customerId == customerId;
}
// Artikel-Dokumente
match /article_documents/{customerId}/{articleId}/{documentId} {
allow read: if request.auth != null && hasCustomerAccess(customerId);
allow write: if request.auth != null
&& hasCustomerAccess(customerId)
&& request.resource.size < 10 * 1024 * 1024 // Max 10 MB
&& request.resource.contentType.matches('application/pdf|image/.*'); // Nur PDF und Bilder
}
// Kunden-Dokumente
match /customer_documents/{customerId}/{documentId} {
allow read: if request.auth != null && hasCustomerAccess(customerId);
allow write: if request.auth != null
&& hasCustomerAccess(customerId)
&& request.resource.size < 20 * 1024 * 1024 // Max 20 MB
&& request.resource.contentType.matches('application/pdf|image/.*|application/vnd\\..*'); // PDF, Bilder, Office
}
// Feed Attachments
match /feed_attachments/{customerId}/{feedId}/{attachmentId} {
allow read: if request.auth != null && hasCustomerAccess(customerId);
allow write: if request.auth != null
&& hasCustomerAccess(customerId)
&& request.resource.size < 50 * 1024 * 1024 // Max 50 MB
&& request.resource.contentType.matches('application/pdf|image/.*|video/.*|audio/.*'); // Multimedia
}
// Explizit: Kein Zugriff auf unbekannte Pfade
match /{allPaths=**} {
allow read, write: if false;
}
}
}
Implementierungsschritte:
1. Backup der aktuellen storage.rules
2. Neue Rules mit Content-Type Validierung erstellen
3. Testing in Emulator
4. Deployment
Erwartete Verbesserung: - ✅ Kein Upload von Malware/Executables - ✅ Konsistente File-Type Beschränkungen - ✅ Schutz vor Storage-Missbrauch
📊 Zusammenfassung & Zeitplan¶
Geschätzter Gesamtaufwand: 9-12 Stunden¶
| Phase | Aufwand | Priorität | Findings |
|---|---|---|---|
| Phase 1: Backend Security | 3-4h | HOCH | #9, #10, #12 |
| Phase 2: Client Security | 4-5h | MITTEL | #8, #14, #15 |
| Phase 3: Connector Security | 2-3h | NIEDRIG | #11, #13 |
Empfohlene Reihenfolge:¶
Woche 1: 1. ✅ JSON.parse Error Handling (#10) - 1h 2. ✅ ERP Firestore Rules härten (#9) - 1.5h 3. ✅ CORS Review & Update (#12) - 1h
Woche 2: 4. ✅ Certificate Pinning (#8) - 2h 5. ✅ Session Management (#14) - 2h
Woche 3: 6. ✅ Content-Type Validierung (#11) - 1.5h 7. ✅ SQL Injection Protection Template (#13) - 1.5h 8. ✅ Firestore Error Handling Audit (#15) - 1h
🧪 Testing-Strategie¶
Automatisierte Tests¶
- Firestore Rules:
firebase emulators:start+ Unit Tests - Storage Rules: Emulator + Upload Tests
- Cloud Functions: Jest Unit Tests für JSON Parsing
- Flutter: Widget Tests für Auth Flows
Manuelle Tests¶
- Certificate Pinning: MITM Proxy (Burp Suite) - Verbindung muss fehlschlagen
- Session Timeout: App 12h+ im Hintergrund lassen
- CORS: cURL Tests von verschiedenen Origins
Security Audit (nach Implementierung)¶
- [ ] Erneuter Durchlauf aller MITTEL-Findings
- [ ] Penetration Testing der gehärteten Firestore Rules
- [ ] Code Review durch zweite Person
- [ ] Update des Security Audit Reports
📝 Dokumentation¶
Nach Implementierung zu aktualisieren:
- ✅ SECURITY_AUDIT_REPORT.md - Status Update auf "BEHOBEN"
- ✅ README.md - Security Features dokumentieren
- ✅ functions/README.md - JSON Utils & Connector Security
- ✅ Inline Code Comments mit "SECURITY:" Marker
❓ Offene Fragen für Implementierung¶
- Firebase Hosting Umgebungen:
- Haben wir separate Dev/Staging/Prod Firebase Projects?
-
Wie erfolgt das Deployment? (CI/CD Pipeline?)
-
Certificate Pinning:
- Müssen wir auch ERP-System anpassen (gleicher Code?)
-
Wie handhaben wir Certificate Rotation bei 10.000+ Nutzern?
-
Session Management:
- Existiert bereits ein AuthService in ERP/Shop?
-
Welche Session-Dauer ist gewünscht? (Vorschlag: 12h)
-
Testing:
- Haben wir eine bestehende Test-Suite?
- Wer führt Security Testing durch?
🚀 Nächste Schritte¶
Zur Freigabe benötigt: 1. Review dieses Konzepts 2. Priorisierung bestätigen oder anpassen 3. Klärung der offenen Fragen 4. Go/No-Go für Implementierung
Nach Freigabe:
1. Branch erstellen: security/mittel-findings
2. Implementation gemäß Phasenplan
3. Testing nach jedem Phase
4. Pull Request mit detailliertem Changelog
5. Security Audit Report aktualisieren
Konzept erstellt am: 24. Februar 2026
Bereit für Review & Implementierung