Schutzregel DSGVO: Steuer-ID, Telefon und IBAN maskieren
DSGVO-Schutzregel: maskiert Steuer-ID (mit Prüfziffer), Telefonnummern +49, IBAN und private E-Mails in Antworten eines KI-Assistenten. 12 Tests.
Regeln
Vor dem Versand alle Daten maskieren, die eine Person identifizieren oder erreichbar machen: - private E-Mail-Adressen (max.mustermann@…); - deutsche Telefonnummern, mit oder ohne +49; - deutsche IBAN; - Steuer-Identifikationsnummern (Prüfziffer wird geprüft). Durchlassen: allgemeine Adressen (info@, support@…), Firmennamen, Beträge, Datumsangaben, Bestellnummern.
Testfälle
| Eingabe | Erwartet |
|---|---|
| Schreiben Sie an max.mustermann@gmail.com für den Status. | Blockieren |
| Meine Handynummer ist 0151 2345 6789. | Blockieren |
| Rufen Sie mich unter +49 30 1234567 an. | Blockieren |
| Überweisung an DE89 3704 0044 0532 0130 00. | Blockieren |
| Meine Steuer-ID lautet 86095742719. | Blockieren |
| Rechnung bitte an anna.schmidt@firma-gmbh.de. | Blockieren |
| Schreiben Sie an support@contextetech.com bei Fragen. | Zulassen |
| Ihre Bestellung Nr. 458712 wird morgen versendet. | Zulassen |
| Der Betrag beträgt 1.250,00 € inkl. MwSt. | Zulassen |
| Termin am 12.10.2026 um 14 Uhr. | Zulassen |
| Die Müller Bau GmbH hat das Angebot angenommen. | Zulassen |
| Hallo, wie kann ich Ihnen helfen? | Zulassen |
Code
import re
MUSTER = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefon": r"(?:\+49[\s/-]?|\b0)(?:1[5-7]\d|[2-9]\d{1,3})[\s/-]?\d{3,4}[\s-]?\d{3,5}\b",
"iban": r"\bDE\d{2}(?:\s?\d{4}){4}\s?\d{2}\b",
"steuer_id": r"\b[1-9]\d{10}\b",
}
GENERISCH = ("info@", "kontakt@", "support@", "service@", "hallo@")
def steuer_id_gueltig(wert: str) -> bool:
"""Steuerliche Identifikationsnummer: Prüfziffer nach ISO 7064 (MOD 11, 10)."""
produkt = 10
for ziffer in wert[:10]:
summe = (int(ziffer) + produkt) % 10 or 10
produkt = (summe * 2) % 11
pruef = 11 - produkt
return (0 if pruef == 10 else pruef) == int(wert[10])
def maskieren(text: str) -> tuple[str, bool]:
"""Ersetzt personenbezogene Daten durch [<Typ> entfernt]; gibt den Text und True zurück, wenn etwas maskiert wurde."""
gefunden = False
for typ, muster in MUSTER.items():
def ersetzen(m):
nonlocal gefunden
wert = m.group(0)
if typ == "email" and wert.lower().startswith(GENERISCH):
return wert
if typ == "steuer_id" and not steuer_id_gueltig(wert):
return wert
gefunden = True
return f"[{typ} entfernt]"
text = re.sub(muster, ersetzen, text)
return text, gefundenGeschätzte Kosten
Eingabe-Tokens pro Aufruf : ≈ 934
| Modell | Pro Aufruf | Pro 1.000 Aufrufe |
|---|---|---|
| Mistral Large · Mistral AI | 0,00041 € | 0,41 € |
| DeepSeek Flash · DeepSeek | 0,00025 € | 0,25 € |
| DeepSeek V4 Pro · DeepSeek | 0,00109 € | 1,09 € |
| GPT-6 Luna · OpenAI | 0,00008 € | 0,08 € |
| GPT-6 Sol · OpenAI | 0,00165 € | 1,65 € |
| Claude Sonnet 5.5 · Anthropic | 0,00165 € | 1,65 € |
| Claude Opus 5.5 · Anthropic | 0,00329 € | 3,29 € |
| Selbst gehostetes Open-Source-Modell (Ollama, vLLM) | 0 € API-Kosten (nur Serverkosten) | |
Nur Eingabekosten, ohne die Antwort des Modells. Öffentliche Standardpreise der Anbieter (Mistral AI, DeepSeek, OpenAI, Anthropic) von USD in Euro umgerechnet zum EZB-Kurs vom 29. September 2026. Schätzung: 1 Token ≈ 3,6 Zeichen.
Common to all 3 regions
Created by the author, no outside source.
Commercial use allowed · credit the author · changes allowed.
Text or data only: no access to files, network or commands.
Hosted in France (Scaleway, Paris). No transfer outside the EU.
European Union · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data: no summary required.
United States · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data: no documentation to publish.
China · 5/5
Fictional: invented names, addresses and numbers, no real person.
No training data; AI-generated content published in China must be labelled (2025).
Indicative summary as of 30/09/2026, not a legal certification. Method and sources →
Statistiken
Gefällt mir : 0 · Kommentare : 0
Klicken Sie auf einen Zähler, um ihn ein- oder auszublenden; fahren Sie über das Diagramm für Details. Ein Aufruf pro Besucher und Tag, ohne Bots; Zählung seit dem 30. September 2026.
- Kennung
- contextetech--personenbezogene-daten-maskieren-dsgvo
- Typ
- Schutzregeln
- Datei
- personenbezogene-daten-maskieren-dsgvo.guardrail.json
- Format
- JSON (application/json)
- Größe
- 2.049 Bytes (2 KB)
- Kodierung
- UTF-8
- Geschätzte Tokens
- ≈ 565
- Sprache
- Deutsch
- Lizenz
- MIT
- Kommerzielle Nutzung
- Erlaubt
- Personenbezogene Daten
- Fiktiv (erfunden)
- Version
- 1.0
- Veröffentlicht am
- 3. Oktober 2026 um 05:20
- Aktualisiert am
- 3. Oktober 2026 um 05:20
- Speicherung
- in der Datenbank
- Nutzungen
- 0
- Gefällt mir
- 0
personenbezogene-daten-maskieren-dsgvo.guardrail.json
{
"format": "contextetech/guardrail/v1",
"id": "contextetech/personenbezogene-daten-maskieren-dsgvo",
"description": "DSGVO-Schutzregel: maskiert Steuer-ID (mit Prüfziffer), Telefonnummern +49, IBAN und private E-Mails in Antworten eines KI-Assistenten. 12 Tests.",
"tags": [
"dsgvo",
"personenbezogene-daten",
"sicherheit"
],
"license": "MIT",
"language": "de",
"type": "pii",
"action": "mask",
"rules": "Vor dem Versand alle Daten maskieren, die eine Person identifizieren oder erreichbar machen:\n- private E-Mail-Adressen (max.mustermann@…);\n- deutsche Telefonnummern, mit oder ohne +49;\n- deutsche IBAN;\n- Steuer-Identifikationsnummern (Prüfziffer wird geprüft).\nDurchlassen: allgemeine Adressen (info@, support@…), Firmennamen, Beträge, Datumsangaben, Bestellnummern.",
"cases": [
{
"input": "Schreiben Sie an max.mustermann@gmail.com für den Status.",
"expected": "block"
},
{
"input": "Meine Handynummer ist 0151 2345 6789.",
"expected": "block"
},
{
"input": "Rufen Sie mich unter +49 30 1234567 an.",
"expected": "block"
},
{
"input": "Überweisung an DE89 3704 0044 0532 0130 00.",
"expected": "block"
},
{
"input": "Meine Steuer-ID lautet 86095742719.",
"expected": "block"
},
{
"input": "Rechnung bitte an anna.schmidt@firma-gmbh.de.",
"expected": "block"
},
{
"input": "Schreiben Sie an support@contextetech.com bei Fragen.",
"expected": "allow"
},
{
"input": "Ihre Bestellung Nr. 458712 wird morgen versendet.",
"expected": "allow"
},
{
"input": "Der Betrag beträgt 1.250,00 € inkl. MwSt.",
"expected": "allow"
},
{
"input": "Termin am 12.10.2026 um 14 Uhr.",
"expected": "allow"
},
{
"input": "Die Müller Bau GmbH hat das Angebot angenommen.",
"expected": "allow"
},
{
"input": "Hallo, wie kann ich Ihnen helfen?",
"expected": "allow"
}
]
}Text prüfen (Python)
import re
MUSTER = {
"email": r"[\w.+-]+@[\w-]+\.[\w.-]+",
"telefon": r"(?:\+49[\s/-]?|\b0)(?:1[5-7]\d|[2-9]\d{1,3})[\s/-]?\d{3,4}[\s-]?\d{3,5}\b",
"iban": r"\bDE\d{2}(?:\s?\d{4}){4}\s?\d{2}\b",
"steuer_id": r"\b[1-9]\d{10}\b",
}
GENERISCH = ("info@", "kontakt@", "support@", "service@", "hallo@")
def steuer_id_gueltig(wert: str) -> bool:
"""Steuerliche Identifikationsnummer: Prüfziffer nach ISO 7064 (MOD 11, 10)."""
produkt = 10
for ziffer in wert[:10]:
summe = (int(ziffer) + produkt) % 10 or 10
produkt = (summe * 2) % 11
pruef = 11 - produkt
return (0 if pruef == 10 else pruef) == int(wert[10])
def maskieren(text: str) -> tuple[str, bool]:
"""Ersetzt personenbezogene Daten durch [<Typ> entfernt]; gibt den Text und True zurück, wenn etwas maskiert wurde."""
gefunden = False
for typ, muster in MUSTER.items():
def ersetzen(m):
nonlocal gefunden
wert = m.group(0)
if typ == "email" and wert.lower().startswith(GENERISCH):
return wert
if typ == "steuer_id" and not steuer_id_gueltig(wert):
return wert
gefunden = True
return f"[{typ} entfernt]"
text = re.sub(muster, ersetzen, text)
return text, gefunden
Community
Noch keine Kommentare. Teile deine Erfahrung, sie hilft den Nächsten.