- Crawler erweitert: +26 neue Dokumente (DSK KP 1-20, SDM V3.1, BfDI Loeschkonzept, BayLDA TOM-Checkliste) - RAG-Queries optimiert: 18 Queries mit EDPB/DSK/WP-Referenzen fuer besseres Retrieval - Chat-Route: queryRAG nutzt jetzt Collection + Query-Boost aus DOCUMENT_RAG_CONFIG - TOM Control Library: 180 Controls in 12 Domaenen (ISO Annex-A Style, tom_controls_v1.json) - Risk Engine Spec: Impact/Likelihood 0-10, Score 0-100, 4 Tiers, Loeschfristen-Engine - Soul-Files: DSK-Kurzpapiere, SDM V3.1, BfDI als primaere deutsche Quellen - Manifest CSV: eu_de_privacy_manifest.csv mit Lizenz-Ampel (gruen/gelb/rot) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20 KiB
Risk Engine Spezifikation -- BreakPilot Compliance
Ueberblick
Die Risk Engine berechnet auf Basis von Impact und Likelihood einen Risiko-Score (0--100), ordnet diesem Score ein Risk-Tier zu und leitet daraus die erforderlichen technisch-organisatorischen Massnahmen (TOM) ab. Sie ergaenzt die bestehende vereinfachte I*L-Bewertung (1--5-Skala) um eine feinere Granularitaet (0--10-Skala).
1. Impact-Heuristik (0--10 Skala)
Der Impact-Wert beschreibt die Schwere des potenziellen Schadens fuer betroffene Personen.
| Faktor | Punkte | DSGVO-Bezug |
|---|---|---|
| Basis-Impact (jede Verarbeitung) | +2 | -- |
| Besondere Datenkategorien (Art. 9) oder Straftaten (Art. 10) | +2 | Art. 9, Art. 10 DSGVO |
| Kinder oder schutzbeduerftige Personen betroffen | +2 | ErwGr. 75, Art. 8 DSGVO |
| Mehr als 10.000 Betroffene | +1 | ErwGr. 91 |
| Automatisierte Einzelentscheidungen / Profiling | +1 | Art. 22 DSGVO |
| Gesundheits- oder Finanzdaten | +1 | Art. 9 Abs. 2 lit. h |
| Systematische Ueberwachung / oeffentlich zugaenglicher Bereich | +1 | Art. 35 Abs. 3 lit. c |
Cap: I = min(Summe, 10)
Beispiel-Berechnung
Szenario: Schul-App mit Schueler-Gesundheitsdaten
Basis = 2
+ Besondere Kategorien (Gesundheit) = +2
+ Kinder betroffen = +2
+ Gesundheitsdaten = +1
-----------------------------------------
Impact (roh) = 7
Impact (nach Cap) = min(7, 10) = 7
Implementierung
interface ImpactContext {
special_categories: boolean; // Art. 9/10 Daten
vulnerable_persons: boolean; // Kinder, Schutzbeduerftige
data_subject_count: number; // Anzahl Betroffene
automated_decisions: boolean; // Art. 22 Profiling
health_or_finance: boolean; // Gesundheits-/Finanzdaten
systematic_monitoring: boolean; // Systematische Ueberwachung
}
function calculateImpact(ctx: ImpactContext): number {
let impact = 2; // Basis
if (ctx.special_categories) impact += 2;
if (ctx.vulnerable_persons) impact += 2;
if (ctx.data_subject_count > 10_000) impact += 1;
if (ctx.automated_decisions) impact += 1;
if (ctx.health_or_finance) impact += 1;
if (ctx.systematic_monitoring) impact += 1;
return Math.min(impact, 10);
}
2. Likelihood-Heuristik (0--10 Skala)
Der Likelihood-Wert beschreibt die Eintrittswahrscheinlichkeit einer Datenschutzverletzung.
| Faktor | Punkte | Begruendung |
|---|---|---|
| Basis-Likelihood (jede Verarbeitung) | +2 | -- |
| Internet-Exponierung (oeffentlich zugaengliche Systeme) | +2 | Groessere Angriffsflaeche |
| Viele Subprozessoren / kein zentrales IAM | +2 | Kontrollverlust, Zugriffschaos |
| Fehlendes Logging / SIEM | +2 | Keine Erkennung von Vorfaellen |
| Cloud ohne Verschluesselung at rest | +1 | Daten bei Breach lesbar |
| Fehlendes Patch-Management / veralteter Software-Stand | +1 | Bekannte Schwachstellen |
| Fehlende Mitarbeiterschulung | +1 | Social Engineering, Fehlbedienung |
Cap: L = min(Summe, 10)
Beispiel-Berechnung
Szenario: Cloud-SaaS ohne zentrale Zugriffsverwaltung
Basis = 2
+ Internet-Exponierung = +2
+ Kein zentrales IAM = +2
+ Cloud ohne Verschluesselung at rest = +1
-----------------------------------------
Likelihood (roh) = 7
Likelihood (nach Cap) = min(7, 10) = 7
Implementierung
interface LikelihoodContext {
internet_exposed: boolean; // Oeffentlich erreichbar
many_subprocessors: boolean; // Viele AVV-Partner / kein IAM
no_logging: boolean; // Kein SIEM / Audit-Log
cloud_unencrypted: boolean; // Cloud ohne Verschluesselung at rest
no_patch_management: boolean; // Veralteter Software-Stand
no_employee_training: boolean; // Keine DS-Schulung
}
function calculateLikelihood(ctx: LikelihoodContext): number {
let likelihood = 2; // Basis
if (ctx.internet_exposed) likelihood += 2;
if (ctx.many_subprocessors) likelihood += 2;
if (ctx.no_logging) likelihood += 2;
if (ctx.cloud_unencrypted) likelihood += 1;
if (ctx.no_patch_management) likelihood += 1;
if (ctx.no_employee_training) likelihood += 1;
return Math.min(likelihood, 10);
}
3. Score-Berechnung
Der Risiko-Score ergibt sich aus dem Produkt von Impact und Likelihood:
Score = round(I * L)
| Parameter | Bereich |
|---|---|
| Impact (I) | 0--10 |
| Likelihood (L) | 0--10 |
| Score | 0--100 |
Implementierung
function calculateRiskScore(impact: number, likelihood: number): number {
return Math.round(
Math.min(impact, 10) * Math.min(likelihood, 10)
);
}
Risiko-Matrix (Impact x Likelihood)
L\I │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10
────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────
2 │ 4 │ 6 │ 8 │ 10 │ 12 │ 14 │ 16 │ 18 │ 20
3 │ 6 │ 9 │ 12 │ 15 │ 18 │ 21 │ 24 │ 27 │ 30
4 │ 8 │ 12 │ 16 │ 20 │ 24 │ 28 │ 32 │ 36 │ 40
5 │ 10 │ 15 │ 20 │ 25 │ 30 │ 35 │ 40 │ 45 │ 50
6 │ 12 │ 18 │ 24 │ 30 │ 36 │ 42 │ 48 │ 54 │ 60
7 │ 14 │ 21 │ 28 │ 35 │ 42 │ 49 │ 56 │ 63 │ 70
8 │ 16 │ 24 │ 32 │ 40 │ 48 │ 56 │ 64 │ 72 │ 80
9 │ 18 │ 27 │ 36 │ 45 │ 54 │ 63 │ 72 │ 81 │ 90
10 │ 20 │ 30 │ 40 │ 50 │ 60 │ 70 │ 80 │ 90 │ 100
4. Risk-Tier Zuordnung
| Score-Range | Tier | Anzahl Controls | Farbe | Beschreibung |
|---|---|---|---|---|
| 0--24 | BASELINE |
~60 Mindestanforderungen | Gruen | Standard-Schutzniveau |
| 25--49 | ENHANCED |
+40 erweiterte Massnahmen | Gelb | Erhoehtes Schutzniveau |
| 50--74 | HIGH_RISK |
+50 Hochrisiko-Pack | Orange | Hohes Risiko, DSFA empfohlen |
| 75--100 | CRITICAL |
+30 Kritisches Pack | Rot | Kritisch, DSFA verpflichtend |
Controls sind kumulativ:
BASELINE= 60 ControlsENHANCED= BASELINE + 40 = 100 ControlsHIGH_RISK= BASELINE + ENHANCED + 50 = 150 ControlsCRITICAL= BASELINE + ENHANCED + HIGH_RISK + 30 = 180 Controls
Implementierung
enum RiskTier {
BASELINE = "BASELINE",
ENHANCED = "ENHANCED",
HIGH_RISK = "HIGH_RISK",
CRITICAL = "CRITICAL",
}
const TIER_ORDER: Record<RiskTier, number> = {
[RiskTier.BASELINE]: 0,
[RiskTier.ENHANCED]: 1,
[RiskTier.HIGH_RISK]: 2,
[RiskTier.CRITICAL]: 3,
};
function scoreTier(score: number): RiskTier {
if (score >= 75) return RiskTier.CRITICAL;
if (score >= 50) return RiskTier.HIGH_RISK;
if (score >= 25) return RiskTier.ENHANCED;
return RiskTier.BASELINE;
}
5. Control-Selection Algorithmus
Der Algorithmus waehlt Controls basierend auf dem Risk-Tier und kontextspezifischen Trigger-Regeln.
Pseudocode
function selectControls(score, context):
tier = scoreTier(score)
controls = allControls.filter(c => c.risk_tier <= tier)
# Trigger-Rules: zusaetzliche Controls je nach Kontext
if context.special_categories:
controls += allControls.filter(c => c.applies_if.field == "special_categories")
if context.third_country_transfer:
controls += allControls.filter(c => c.applies_if.field == "third_country_transfer")
if context.large_scale:
controls += allControls.filter(c => c.applies_if.field == "large_scale")
if context.vulnerable_persons:
controls += allControls.filter(c => c.applies_if.field == "vulnerable_persons")
return deduplicate(controls)
Implementierung
interface Control {
id: string;
title: string;
description: string;
risk_tier: RiskTier;
domain: TOMDomain;
applies_if?: {
field: string;
value: boolean;
};
}
interface SelectionContext {
score: number;
special_categories: boolean;
third_country_transfer: boolean;
large_scale: boolean;
vulnerable_persons: boolean;
}
function selectControls(
allControls: Control[],
ctx: SelectionContext
): Control[] {
const tier = scoreTier(ctx.score);
const tierLevel = TIER_ORDER[tier];
// 1. Tier-basierte Auswahl (kumulativ)
const tierControls = allControls.filter(
(c) => TIER_ORDER[c.risk_tier] <= tierLevel
);
// 2. Trigger-basierte Zusatz-Controls
const triggerFields: (keyof SelectionContext)[] = [
"special_categories",
"third_country_transfer",
"large_scale",
"vulnerable_persons",
];
const triggerControls = allControls.filter((c) => {
if (!c.applies_if) return false;
const field = c.applies_if.field as keyof SelectionContext;
return triggerFields.includes(field) && ctx[field] === true;
});
// 3. Deduplizieren
const controlMap = new Map<string, Control>();
[...tierControls, ...triggerControls].forEach((c) => {
controlMap.set(c.id, c);
});
return Array.from(controlMap.values());
}
Trigger-Rules im Detail
| Trigger | Zusaetzliche Controls | Beispiel |
|---|---|---|
special_categories |
Erweiterte Zugriffskontrolle, Verschluesselung, DSFA-Pflicht | Gesundheitsdaten in HR-System |
third_country_transfer |
SCCs, TIA, Binding Corporate Rules | US-Cloud-Anbieter |
large_scale |
DPO-Pflicht, erweitertes Monitoring, Kapazitaetsplanung | >100.000 Betroffene |
vulnerable_persons |
Altersverifikation, elterliche Einwilligung, kindgerechte UI | Schul-App |
6. Loeschfristen-Engine
Die Loeschfristen-Engine bestimmt automatisch Aufbewahrungsfristen und Loeschzeitpunkte.
Berechnung der Aufbewahrungsfrist
RetentionPeriod = max(legal_minimum, operational_need)
Loeschausloeser (DeletionTrigger)
| Trigger | Beschreibung | Beispiel |
|---|---|---|
Vertragsende |
Ende der Vertragsbeziehung | Schueler verlaesst Schule |
Zweckwegfall |
Verarbeitungszweck entfaellt | Projekt abgeschlossen |
Widerruf |
Betroffener widerruft Einwilligung | Einwilligung zurueckgezogen |
Ausnahmeregeln (ExceptionRules)
| Rechtsgrundlage | Frist | Datenkategorie |
|---|---|---|
| HGB Par. 257 (Handelsbuecher) | 10 Jahre | Buchungsbelege, Jahresabschluesse |
| AO Par. 147 (Abgabenordnung) | 10 Jahre | Steuerrelevante Unterlagen |
| AO Par. 147 (sonstige Unterlagen) | 6 Jahre | Geschaeftsbriefe |
| BetrVG (Betriebsrat) | 3 Jahre | Betriebsratsprotokolle |
| BDSG Par. 35 | Unverzueglich | Nicht mehr benoetigte personenbezogene Daten |
| Rechtsstreit-Hold | Bis Abschluss | Alle prozessrelevanten Daten |
Default-Retention je Datenkategorie
| Datenkategorie | Default-Frist | Gesetzliche Grundlage |
|---|---|---|
| Stammdaten (Name, Adresse) | 3 Jahre nach Vertragsende | DSGVO Art. 17, Verjaehrung Par. 195 BGB |
| Vertragsdaten | 10 Jahre | HGB Par. 257 |
| Rechnungsdaten | 10 Jahre | AO Par. 147 |
| Kommunikationsdaten (E-Mails) | 6 Jahre | AO Par. 147 |
| Bewerberdaten | 6 Monate | AGG Par. 15 Abs. 4 |
| Log-Daten (Server, Zugriff) | 90 Tage | DSGVO Art. 5 Abs. 1 lit. e |
| Gesundheitsdaten | 10 Jahre | Aerztliche Aufbewahrungspflicht |
| Schulnoten / Zeugnisse | 10 Jahre nach Abgang | Landesschulgesetze |
| Einwilligungen (Nachweis) | 3 Jahre nach Widerruf | DSGVO Art. 7 Abs. 1, Beweislast |
| Video-Ueberwachung | 72 Stunden | BDSG Par. 4 Abs. 5 |
Implementierung
interface RetentionRule {
category: string;
default_days: number;
legal_basis: string;
deletion_trigger: "Vertragsende" | "Zweckwegfall" | "Widerruf";
exception_rules: ExceptionRule[];
}
interface ExceptionRule {
condition: string; // z.B. "Rechtsstreit-Hold"
override_days: number; // -1 = unbegrenzt bis Bedingung entfaellt
legal_basis: string;
}
function calculateDeletionDate(
rule: RetentionRule,
triggerDate: Date,
activeExceptions: ExceptionRule[]
): Date | null {
// Aktive Ausnahmen pruefen
const holdException = activeExceptions.find(
(e) => e.override_days === -1
);
if (holdException) return null; // Loeschung ausgesetzt
// Maximale Frist berechnen
const retentionDays = Math.max(
rule.default_days,
...activeExceptions.map((e) => e.override_days)
);
const deletionDate = new Date(triggerDate);
deletionDate.setDate(deletionDate.getDate() + retentionDays);
return deletionDate;
}
7. Mapping: Score → TOM-Domaenen → Textbausteine
TOM-Domaenen nach SDM (Standard-Datenschutzmodell)
| Domaene | Beschreibung | SDM-Gewaehrleistungsziel |
|---|---|---|
ZUGANG |
Zugangskontrolle | Vertraulichkeit |
ZUGRIFF |
Zugriffskontrolle | Vertraulichkeit |
UEBERTRAGUNG |
Weitergabekontrolle | Integritaet |
EINGABE |
Eingabekontrolle | Integritaet |
AUFTRAG |
Auftragskontrolle | Integritaet |
VERFUEGBARKEIT |
Verfuegbarkeitskontrolle | Verfuegbarkeit |
TRENNUNG |
Trennungskontrolle | Nichtverkettung |
TRANSPARENZ |
Transparenzkontrolle | Transparenz |
INTERVENIERBARKEIT |
Betroffenenrechte | Intervenierbarkeit |
DATENMINIMIERUNG |
Datenminimierung | Datenminimierung |
Tier → Domaenen-Zuordnung
| Domaene | BASELINE | ENHANCED | HIGH_RISK | CRITICAL |
|---|---|---|---|---|
| ZUGANG | Pflicht | Pflicht | Pflicht | Pflicht |
| ZUGRIFF | Pflicht | Pflicht | Pflicht | Pflicht |
| UEBERTRAGUNG | Pflicht | Pflicht | Pflicht | Pflicht |
| EINGABE | Empfohlen | Pflicht | Pflicht | Pflicht |
| AUFTRAG | Empfohlen | Pflicht | Pflicht | Pflicht |
| VERFUEGBARKEIT | Pflicht | Pflicht | Pflicht | Pflicht |
| TRENNUNG | Empfohlen | Empfohlen | Pflicht | Pflicht |
| TRANSPARENZ | Pflicht | Pflicht | Pflicht | Pflicht |
| INTERVENIERBARKEIT | Pflicht | Pflicht | Pflicht | Pflicht |
| DATENMINIMIERUNG | Empfohlen | Pflicht | Pflicht | Pflicht |
Textbausteine je Tier und Domaene (Auszug)
const TOM_TEXTBAUSTEINE: Record<RiskTier, Record<string, string[]>> = {
BASELINE: {
ZUGANG: [
"Passwortrichtlinie mit Mindestlaenge 12 Zeichen",
"Automatische Bildschirmsperre nach 5 Minuten",
"Besuchermanagement mit Protokollierung",
],
ZUGRIFF: [
"Rollenbasierte Zugriffskontrolle (RBAC)",
"Need-to-know-Prinzip",
"Regelmaessige Ueberpruefung der Berechtigungen (jaehrlich)",
],
VERFUEGBARKEIT: [
"Taegliche Backups mit Integritaetspruefung",
"USV-Anlage fuer kritische Systeme",
"Dokumentierter Notfallplan",
],
},
ENHANCED: {
ZUGANG: [
"Multi-Faktor-Authentifizierung (MFA) fuer alle Nutzer",
"Zentrales Identity Management (IdP)",
"Hardware-Token oder FIDO2 fuer Admin-Zugaenge",
],
ZUGRIFF: [
"Attributbasierte Zugriffskontrolle (ABAC)",
"Privileged Access Management (PAM)",
"Quartalsweise Zugriffs-Reviews",
],
VERFUEGBARKEIT: [
"Geo-redundante Backups",
"Recovery Time Objective (RTO) < 4 Stunden",
"Jaehrlicher Disaster-Recovery-Test",
],
},
HIGH_RISK: {
ZUGANG: [
"Zero-Trust-Architektur",
"Biometrische Zugangskontrolle fuer Serverraeume",
"Netzwerksegmentierung mit Mikrosegmenten",
],
ZUGRIFF: [
"Just-in-Time Access (zeitlich begrenzte Berechtigungen)",
"Vier-Augen-Prinzip fuer kritische Operationen",
"Echtzeit-Anomalieerkennung bei Zugriffen",
],
TRENNUNG: [
"Mandantentrennung auf Datenbankebene (Schemata)",
"Getrennte Verschluesselungsschluessel je Mandant",
"Isolierte Verarbeitungsumgebungen",
],
},
CRITICAL: {
ZUGANG: [
"Air-Gapped Systeme fuer kritischste Daten",
"24/7 SOC-Ueberwachung",
"Penetrationstests (quartalsweise, extern)",
],
ZUGRIFF: [
"Hardware Security Modules (HSM) fuer Schluessel",
"Break-Glass-Verfahren mit Audit-Trail",
"Kontinuierliche Authentifizierung",
],
VERFUEGBARKEIT: [
"Active-Active Cluster mit automatischem Failover",
"RTO < 15 Minuten, RPO < 5 Minuten",
"Monatliche Disaster-Recovery-Tests",
],
},
};
8. Kompatibilitaet mit bestehendem Modell
Bestehendes Modell (backend-compliance)
Das bestehende Modell in backend-compliance/compliance/db/models.py nutzt eine vereinfachte Skala:
| Parameter | Bestehend | Neu (diese Spec) |
|---|---|---|
| Impact-Skala | 1--5 | 0--10 |
| Likelihood-Skala | 1--5 | 0--10 |
| Score-Bereich | 1--25 | 0--100 |
| Schwellenwerte | 6 / 12 / 20 | 25 / 50 / 75 |
Konvertierung: Alte Skala → Neue Skala
// Alt (1-5) → Neu (0-10)
function oldToNewScale(oldValue: number): number {
return Math.round((oldValue / 5) * 10);
}
// Neu (0-10) → Alt (1-5)
function newToOldScale(newValue: number): number {
return Math.max(1, Math.round((newValue / 10) * 5));
}
Konvertierung: Alter Score → Neuer Score
// Alt (1-25) → Neu (0-100)
function oldScoreToNew(oldScore: number): number {
return Math.round((oldScore / 25) * 100);
}
// Neu (0-100) → Alt (1-25)
function newScoreToOld(newScore: number): number {
return Math.max(1, Math.round((newScore / 100) * 25));
}
Schwellenwert-Mapping
| Altes Tier (1--25) | Neues Tier (0--100) | Risk-Tier |
|---|---|---|
| 1--5 | 0--24 | BASELINE |
| 6--11 | 25--49 | ENHANCED |
| 12--19 | 50--74 | HIGH_RISK |
| 20--25 | 75--100 | CRITICAL |
Migrations-Strategie
Bei der Migration bestehender Risikobewertungen:
-- Bestehende Scores konvertieren (1-25 → 0-100)
UPDATE compliance_risks
SET score_v2 = ROUND((score::numeric / 25.0) * 100)
WHERE score_v2 IS NULL;
-- Impact/Likelihood konvertieren (1-5 → 0-10)
UPDATE compliance_risks
SET impact_v2 = ROUND((impact::numeric / 5.0) * 10),
likelihood_v2 = ROUND((likelihood::numeric / 5.0) * 10)
WHERE impact_v2 IS NULL;
Anhang A: Vollstaendiges Berechnungsbeispiel
Szenario: Lernplattform mit KI-Korrekturvorschlaegen
Kontext:
- Schueler-Plattform (Kinder betroffen)
- KI bewertet Klausuren (automatisierte Entscheidung)
- Gesundheitsdaten bei Attestverwaltung
- Cloud-Hosting (AWS Frankfurt)
- MFA vorhanden, aber kein SIEM
Impact-Berechnung:
Basis = 2
+ Kinder / Schutzbeduerftige = +2
+ Automatisierte Entscheidungen = +1
+ Gesundheitsdaten = +1
+ Besondere Kategorien (Art. 9) = +2
─────────────────────────────────────
Impact = min(8, 10) = 8
Likelihood-Berechnung:
Basis = 2
+ Internet-Exponierung = +2
+ Fehlendes Logging / SIEM = +2
─────────────────────────────────────
Likelihood = min(6, 10) = 6
Score und Tier:
Score = round(8 * 6) = 48 → Tier: ENHANCED
Ausgewaehlte Controls: 100 (60 BASELINE + 40 ENHANCED)
plus Trigger-Controls fuer special_categories und vulnerable_persons.
Empfohlene Massnahmen (Auszug):
- MFA fuer alle Nutzer (bereits vorhanden)
- SIEM-System einfuehren (fehlend -- Prioritaet hoch)
- Altersverifikation und elterliche Einwilligung
- DSFA durchfuehren (Art. 35 -- Kinder + automatisierte Entscheidung)
- Erklaerbarkeit der KI-Entscheidungen sicherstellen (AI Act)
Anhang B: Glossar
| Begriff | Erklaerung |
|---|---|
| TOM | Technisch-organisatorische Massnahmen (Art. 32 DSGVO) |
| DSFA | Datenschutz-Folgenabschaetzung (Art. 35 DSGVO) |
| SDM | Standard-Datenschutzmodell der Datenschutzkonferenz |
| IAM | Identity and Access Management |
| SIEM | Security Information and Event Management |
| SCCs | Standard Contractual Clauses (Standardvertragsklauseln) |
| TIA | Transfer Impact Assessment |
| AVV | Auftragsverarbeitungsvertrag (Art. 28 DSGVO) |
| RBAC | Role-Based Access Control |
| ABAC | Attribute-Based Access Control |
| PAM | Privileged Access Management |
| HSM | Hardware Security Module |
| SOC | Security Operations Center |
| RTO | Recovery Time Objective |
| RPO | Recovery Point Objective |