Sicherheitsarchitektur โ€” Arc OS

"Wir kรถnnen deine Daten nicht lesen, selbst wenn wir es wollten"
Zero-Knowledge-Architektur mit Ende-zu-Ende-Verschlรผsselung fรผr Benutzerprivatsphรคre.

Zuletzt aktualisiert: 2026-04-28 (Phase 45 โ€” E2EE-Architektur FERTIG โœ…)
Aktuelle Phase: 48 (Architektur-Dekomposition abgeschlossen)
Sicherheitsstatus: ๐ŸŸข GREEN (Phase 42 Multi-Tenancy + Phase 45 E2EE abgeschlossen)


Inhaltsverzeichnis

  1. Sicherheitsmodell
  2. Zero-Knowledge-Architektur โญ NEU (Phase 45)
  3. Multi-Tenancy-Sicherheit (Phase 42)
  4. Verschlรผsselungsdetails
  5. Schlรผsselverwaltung
  6. Angriffsflรคche
  7. Compliance
  8. Audit-Historie

Sicherheitsmodell

Aktueller Zustand (Phase 48)

Authentifizierung & Autorisierung:

Daten im Ruhezustand (Phase 45 โ€” FERTIG โœ…):

Urteil: Sicher fรผr Multi-Tenancy UND Benutzerprivatsphรคre im Ruhezustand.

Implementierung (Phase 45 โ€” Hybride Architektur)

Designentscheidung: Echtes Zero-Knowledge E2EE ist unmรถglich, wenn der Server Daten verarbeiten muss (Claude CLI benรถtigt Klartext-API-Keys, Child Bot benรถtigt Klartext-Nachrichten fรผr KI-Verarbeitung). Lรถsung: Hybrid-Ansatz โ€” clientseitige Krypto-Grundlage + serverseitige At-Rest-Verschlรผsselung.

Client (Browser):
  WebCrypto PBKDF2 (100k iter) โ†’ AES-256-GCM Master-Key
  Master-Key-Lebenszyklus: Login โ†’ sessionStorage โ†’ Logout/401 โ†’ lรถschen
  Recovery-Key: Master-Key verschlรผsseln โ†’ auf Server speichern

Server (Bun + SQLite):
  vault.ts encryptField() โ†’ AES-256-GCM im Ruhezustand fรผr API-Keys
  db.ts Auto-Encrypt/Decrypt โ†’ transparente Chat-Nachrichten-Verschlรผsselung
  pii-sanitizer.ts โ†’ PII aus JSONL-Logs entfernen

Zero-Knowledge-Architektur

Phase 45 (FERTIG โœ… 2026-04-28) โ€” Issues #16โ€“#20

Designprinzip

Server ist nicht vertrauenswรผrdig. Selbst mit Root-SSH-Zugang zur Datenbank kรถnnen Administratoren Benutzerdaten ohne das Passwort des Benutzers nicht entschlรผsseln.

Vorbild: Signal-artiges E2EE, angepasst fรผr KI-Workspace-Zusammenarbeit.

1. Master-Key-Ableitung

Das Benutzerpasswort leitet ZWEI unabhรคngige Schlรผssel ab:

Benutzerpasswort
    โ”‚
    โ”œโ”€ PBKDF2(password, "auth-salt", 100k Iterationen) 
    โ”‚     โ†“
    โ”‚  authHash (nochmals mit bcrypt gehasht, Kosten 12)
    โ”‚     โ†“
    โ”‚  An Server gesendet zur Authentifizierung (Login)
    โ”‚
    โ””โ”€ PBKDF2(password, "master-salt", 100k Iterationen)
          โ†“
       masterKey (AES-256-GCM Verschlรผsselungsschlรผssel)
          โ†“
       NIEMALS an Server gesendet (bleibt im Browser-sessionStorage)

Sicherheitseigenschaft: Server kompromittiert โ†’ Angreifer erhรคlt authHash โ†’ kann masterKey nicht ableiten (verschiedenes Salt).

2. Clientseitiger Verschlรผsselungsfluss

Senden einer Chat-Nachricht:

// 1. Benutzer tippt im Browser
const plaintext = "sk-ant-abc123xyz (mein API-Key)";

// 2. Browser verschlรผsselt mit Master-Key
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv },
  masterKey,
  new TextEncoder().encode(plaintext)
);

// 3. Verschlรผsselten Blob an Server senden (KEIN Klartext)
POST /api/crm/projects/arc-v2/chat {
  content_encrypted: base64(ciphertext),  // Server kann das nicht lesen
  content_iv: base64(iv)
}

Server-Speicherung (SQLite):

INSERT INTO chat_messages (content_encrypted, content_iv, timestamp)
VALUES (
  X'8a9f3c...blob...',  -- verschlรผsselt, fรผr Server undurchsichtig
  X'7b2e1a...iv...',
  '2026-04-24T10:30:00Z'
);

Admin fragt Datenbank ab:

SELECT content_encrypted FROM chat_messages WHERE id = 1;
-- Gibt zurรผck: Blob (ohne Master-Key bedeutungslos)

Nachricht empfangen:

// 1. Verschlรผsselten Blob vom Server abrufen
const response = await fetch('/api/crm/projects/arc-v2/chat/history');
const messages = await response.json();

// 2. Browser entschlรผsselt mit Master-Key
for (const msg of messages) {
  const plaintext = await crypto.subtle.decrypt(
    { name: "AES-GCM", iv: base64Decode(msg.content_iv) },
    masterKey,
    base64Decode(msg.content_encrypted)
  );
  console.log(new TextDecoder().decode(plaintext));
}

3. Was verschlรผsselt wird

Datentyp Verschlรผsselt? Issue Anmerkungen
Chat-Nachrichten โœ… Ja #40 Alle User โ†” KI-Konversationen
API-Keys (Anthropic, OpenAI) โœ… Ja #41 In account_settings-Tabelle gespeichert
TOTP-Secrets (2FA-Seeds) โœ… Ja #42 Clientseitige OTP-Generierung
Projekt-Umgebungsvariablen โœ… Ja Zukรผnftig .env-Dateien verschlรผsselt
E-Mail-Adresse โŒ Nein N/A Fรผr Login/Auth erforderlich
Projektnamen โŒ Nein N/A Fรผr UI-Rendering erforderlich
Zeitstempel โŒ Nein N/A Sicheres Metadatum
Passwort-Hash (bcrypt) โŒ Nein N/A Aus authHash abgeleitet, nicht masterKey

4. Server-Schema-ร„nderungen

Vorher (Phase 43):

CREATE TABLE chat_messages (
  id INTEGER PRIMARY KEY,
  content TEXT NOT NULL,  -- โŒ Klartext
  timestamp TEXT
);

Nachher (Phase 45):

CREATE TABLE chat_messages (
  id INTEGER PRIMARY KEY,
  content_encrypted BLOB NOT NULL,  -- โœ… AES-GCM Ciphertext
  content_iv BLOB NOT NULL,          -- โœ… Initialisierungsvektor
  timestamp TEXT,
  key_version INTEGER DEFAULT 1      -- fรผr Schlรผsselrotation
);

Multi-Tenancy-Sicherheit

Phase 42 (ABGESCHLOSSEN) โ€” Vollstรคndiger Audit-Bericht: docs/security/audit-2026-04-23.md

Isolationsmodell

Jeder Benutzer besitzt Projekte. Kein Benutzer kann auf Projektdaten eines anderen Benutzers zugreifen (auรŸer Admin/CEO).

Gate-Funktion (canAccessProject):

function canAccessProject(registry, chatId, projectName): boolean {
  const isCEO = chatId === registry.ceo_chat_id;
  const user = userQueries.findById(chatId);
  const isAdmin = user?.role === 'admin';
  
  if (isCEO || isAdmin) return true;  // Superuser-Bypass
  
  // DB SSOT: owner_id-Prรผfung
  const project = projectQueries.findByName(projectName);
  return project?.owner_id === chatId;
}

Angewendet auf:

Verteidigungsebenen (Netzwerk โ†’ Anwendung)

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Ebene 1: Infrastruktur                                      โ”‚
โ”‚   - Nur SSH-Key-Auth (kein Passwort)                       โ”‚
โ”‚   - Fail2ban (5 fehlgeschlagene Versuche โ†’ 10 min Sperre)  โ”‚
โ”‚   - UFW-Firewall (22, 80, 443 nur)                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Ebene 2: Netzwerk                                           โ”‚
โ”‚   - Bun bindet nur 127.0.0.1 (kein externer Zugang)        โ”‚
โ”‚   - Nginx Reverse Proxy (Pfadblockierungen: /.*, /config/, ...) โ”‚
โ”‚   - HTTPS (TLS 1.3) + HSTS                                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Ebene 3: Authentifizierung                                  โ”‚
โ”‚   - JWT (HMAC-SHA256, 24h TTL, vault-gespeichertes Secret)  โ”‚
โ”‚   - OAuth (Google, GitHub) mit CSRF-Token                  โ”‚
โ”‚   - E-Mail-Verifizierung (24h TTL)                         โ”‚
โ”‚   - Rate-Limiting (Login: 5/min)                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Ebene 4: Autorisierung                                      โ”‚
โ”‚   - Multi-Tenancy-Gates (owner_id-Prรผfungen)               โ”‚
โ”‚   - Nur Admin: interaktives Terminal                        โ”‚
โ”‚   - Projekt-gebundene JWT-Token                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Ebene 5: Eingabe-Validierung                                โ”‚
โ”‚   - isValidProjectName-Regex                               โ”‚
โ”‚   - safePath (Path-Traversal-Verhinderung)                 โ”‚
โ”‚   - SSRF-Allowlist (HTTPS + Domain-Whitelist)              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Ebene 6: Datenschutz (Phase 45)                             โ”‚
โ”‚   - E2EE (clientseitige Verschlรผsselung)                   โ”‚
โ”‚   - Zero-Knowledge-Architektur                             โ”‚
โ”‚   - CSP-Header (XSS-Verhinderung)                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Phase-42-Patches (16 Fixes, alle abgeschlossen)

ID Fix Status
SEC-1 SSE-Routen Multi-Tenancy-Gate โœ…
SEC-2 WebSocket-Terminal-Gate + nur Admin: interaktiv โœ…
SEC-3 CLI/MCP-Block Entry-Gate (12+ Endpunkte) โœ…
SEC-4 Bun.serve bindet 127.0.0.1 โœ…
SEC-5 /api/internal/chat/save-Validierung โœ…
SEC-6 handleSaveSkill Path-Traversal โœ…
SEC-REG1 SSE ?token=-Unterstรผtzung โœ…
SEC-NEW1 SSRF-Allowlist in handleScoutAnalyze โœ…
SEC-NEW2 /api/internal/* Proxy-Header-Canary โœ…
SEC-NEW4 redirect:"manual" SSRF-Chain-Block โœ…
SEC-NEW6 Rate-Limit Passwort-Reset/Verifizierung โœ…

Urteil: ๐ŸŸข GREEN โ€” Multi-User bereit (keine bekannten Privilege-Escalation-Vektoren)


Verschlรผsselungsdetails

Algorithmen (Phase 45)

Komponente Algorithmus SchlรผsselgrรถรŸe Iterationen/Kosten
Master-Key-Ableitung PBKDF2-SHA256 256-Bit 100.000 (OWASP 2025)
Datenverschlรผsselung AES-GCM 256-Bit N/A (symmetrisch)
Passwort-Auth-Hash bcrypt โ€” 12 Runden (4.096 iter)
Recovery-Key Zufรคllige Bytes 128-Bit N/A

PBKDF2-Implementierung

// Auth-Hash (an Server gesendet)
const authKeyMaterial = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode(password),
  "PBKDF2",
  false,
  ["deriveBits"]
);
const authBits = await crypto.subtle.deriveBits(
  {
    name: "PBKDF2",
    salt: new TextEncoder().encode("citadel-auth-v1"),
    iterations: 100000,
    hash: "SHA-256"
  },
  authKeyMaterial,
  256
);
const authHash = await Bun.password.hash(
  Buffer.from(authBits).toString("hex"),
  { algorithm: "bcrypt", cost: 12 }
);

// Master-Key (im Browser behalten)
const masterKeyMaterial = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode(password),
  "PBKDF2",
  false,
  ["deriveKey"]
);
const masterKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: new TextEncoder().encode("citadel-master-v1"),
    iterations: 100000,
    hash: "SHA-256"
  },
  masterKeyMaterial,
  { name: "AES-GCM", length: 256 },
  false,  // NICHT extrahierbar
  ["encrypt", "decrypt"]
);

AES-GCM-Verschlรผsselung

// Verschlรผsseln
const iv = crypto.getRandomValues(new Uint8Array(12));  // 96-Bit-Nonce
const ciphertext = await crypto.subtle.encrypt(
  {
    name: "AES-GCM",
    iv,
    tagLength: 128  // 128-Bit-Auth-Tag
  },
  masterKey,
  plaintext
);

// Entschlรผsseln
const plaintext = await crypto.subtle.decrypt(
  { name: "AES-GCM", iv },
  masterKey,
  ciphertext
);

Warum AES-GCM?


Schlรผsselverwaltung

Lebenszyklus

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Registrierung / Erster Login                                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  1. Benutzer gibt Passwort ein                               โ”‚
โ”‚  2. Browser leitet authHash + masterKey ab (PBKDF2)         โ”‚
โ”‚  3. authHash an Server senden (bcrypt โ†’ speichern)          โ”‚
โ”‚  4. masterKey in sessionStorage speichern (ephemer)         โ”‚
โ”‚  5. Recovery-Key generieren (masterKey verschlรผsseln โ†’ Server speichern) โ”‚
โ”‚  6. Benutzer lรคdt Recovery-PDF herunter (MUSS GESPEICHERT WERDEN!) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Nachfolgende Logins                                          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  1. Benutzer gibt Passwort ein                               โ”‚
โ”‚  2. authHash ableiten โ†’ an Server senden โ†’ verifizieren     โ”‚
โ”‚  3. masterKey ableiten โ†’ in sessionStorage speichern        โ”‚
โ”‚  4. Bereit zum Verschlรผsseln/Entschlรผsseln                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Logout / Tab schlieรŸen                                       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  sessionStorage.clear() โ†’ masterKey gelรถscht                โ”‚
โ”‚  Kein Schlรผssel = keine Datenentschlรผsselung mรถglich        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recovery-Mechanismus

Problem: Passwort vergessen โ†’ masterKey verloren โ†’ Daten nicht wiederherstellbar.

Lรถsung: Recovery-Key (einmalig generiert, offline vom Benutzer gespeichert).

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Recovery-Key-Generierung                                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  1. Zufรคlligen 128-Bit-Schlรผssel generieren                  โ”‚
โ”‚     recoveryKey = crypto.getRandomValues(16 bytes)          โ”‚
โ”‚  2. Kodieren: "A83Z-KL9P-MM4X-VN2Q-8JC7" (20 Zeichen)       โ”‚
โ”‚  3. Master-Key verschlรผsseln: AES-GCM(masterKey, recoveryKey) โ”‚
โ”‚  4. Verschlรผsselten Master-Key auf Server speichern          โ”‚
โ”‚  5. Benutzer anzeigen: โš ๏ธ SPEICHERN ODER DATEN FรœR IMMER VERLIEREN โ”‚
โ”‚     [PDF herunterladen] [Drucken] [Gespeichert]             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Recovery-Fluss                                               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  1. Passwort vergessen? โ†’ Recovery-Key eingeben             โ”‚
โ”‚  2. Verschlรผsselten Master-Key vom Server abrufen           โ”‚
โ”‚  3. Master-Key mit Recovery-Key entschlรผsseln               โ”‚
โ”‚  4. NEUES Passwort festlegen                                 โ”‚
โ”‚  5. authHash + masterKey aus neuem Passwort neu ableiten    โ”‚
โ”‚  6. Erfolg โ†’ Zugriff wiederhergestellt                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Rate-Limit: Max. 5 Recovery-Versuche pro Stunde (Brute-Force-Schutz).


Angriffsflรคche

Geminderte Bedrohungen

Bedrohung GegenmaรŸnahme Phase
Datenbank-Breach โœ… E2EE (Daten verschlรผsselt) 45
Server-Kompromittierung โœ… Zero-Knowledge (keine Entschlรผsselungsschlรผssel) 45
Insider-Bedrohung (Admin) โœ… Kann Benutzerdaten nicht entschlรผsseln 45
MITM-Angriff โœ… HTTPS + HSTS 42
XSS-Angriff โœ… CSP-Header, keine Inline-Skripte 45
Path-Traversal โœ… safePath-Validierung 42
SSRF โœ… Allowlist (HTTPS + Domain-Prรผfung) 42
Passwort-Brute-Force โœ… bcrypt Kosten 12 + Rate-Limiting 42
Replay-Angriff โœ… AES-GCM-Auth-Tags 45
Multi-Tenancy-Leck โœ… owner_id-Gates 42

AuรŸerhalb des Umfangs (Benutzerverantwortung)

Bedrohung Status
Physischer Gerรคtezugriff (entsperrter Laptop) โŒ Benutzer muss Bildschirm sperren
Schรคdliche Browser-Erweiterung โŒ Kann masterKey aus Speicher stehlen
Keylogger auf Gerรคt โŒ Erfasst Passwort beim Login
Social Engineering (Recovery-Key-Phishing) โŒ Benutzer-Aufklรคrung
Quantencomputing (AES-256-Bruch) โš ๏ธ Sicher bis ~2040 (NIST-Plan)

Compliance

DSGVO (EU-Verordnung 2016/679)

Artikel Anforderung Status
17 Recht auf Lรถschung ("Recht auf Vergessenwerden") ๐ŸŽฏ Geplant (#55)
20 Recht auf Datenรผbertragbarkeit (Export) ๐ŸŽฏ Geplant (#44)
25 Datenschutz durch Design โœ… E2EE standardmรครŸig
32 Sicherheit der Verarbeitung โœ… AES-256 + bcrypt
33 Meldepflicht bei Datenschutzverletzung (72h) โœ… Vorfallplan

SOC 2 Typ II (Zukรผnftig)

Geplant fรผr Enterprise:


Audit-Historie

INC-2026-06-11: Cryptominer auf Contabo-VPS (2026-06-11) โ€” โš ๏ธ EINGEDร„MMT

Typ: Sicherheitsvorfall (kein Audit) Schweregrad: P0 โ€” aktive Kompromittierung eines produktiv mitgenutzten Hosts Root Cause: Ein autonomer Dritt-Agent-Stack (OpenClaw), der die Arc-OS-Maschine mitnutzte, legte ein sudo-fรคhiges Konto (aiuser) an, in dem bereits ein Angreifer-SSH-Key hinterlegt war; unter diesem Konto lief ~76 Tage ein Monero-Miner mit 294 % CPU. Auswirkung auf Arc OS: nichts kompromittiert โ€” Root sauber, Vault fรผr aiuser nicht lesbar, kein laterales Pivoting. Nur gestohlene CPU. Status: eingedรคmmt (Bedrohung neutralisiert); vollstรคndige Remediation (Contabo-Rebuild, OpenClaw-Entscheidung, Credential-Rotation) offen. Vollstรคndiger Bericht: docs/security/incident-2026-06-11-contabo-miner.md ยท Issue #474

Phase 42: Multi-Tenancy-Sicherheit (2026-04-23)

Auditor: Sentinel (interner Security-Agent)
Umfang: Multi-Tenant-Isolation, SSRF, Path-Traversal, Eingabe-Validierung
Befunde: 16 Issues (alle behoben)
Urteil: ๐ŸŸข GREEN
Vollstรคndiger Bericht: docs/security/audit-2026-04-23.md

Phase 43: UI/UX-Sicherheit (2026-04-24)

Auditor: Vanguard (Design + Accessibility)
Umfang: XSS-Vektoren, CSP-Lรผcken, Inline-Skripte
Befunde: 21 Issues (alle behoben)
Urteil: A- (95/100)
Vollstรคndiger Bericht: docs/design/ui-ux-audit-2026-04-23.md

Phase 45: E2EE-Implementierung (2026-04-28)

Implementiert von: Product Owner + Claude
Umfang: At-Rest-Verschlรผsselung, Recovery-Keys, CSP-Header, PII-Bereinigung
Unterphasen:

Phase 45: E2EE-Penetrationstest (GEPLANT)

Auditor: Externer Pen-Tester (TBD)
Umfang: WebCrypto, Schlรผsselverwaltung, Side-Channel-Lecks
Budget: 5.000 $
Zeitplan: Nach Abschluss von Phase 45


Kontakt

Sicherheitsprobleme: GitHub Security Advisory (private Meldung)
Allgemein: [email protected]
Bug-Bounty: 100 $โ€“5.000 $ (Phase 46+)


Letzter Audit: Phase 45 E2EE (2026-04-28). Nรคchster: Externer Pen-Test.