Lokale KI: Wo kleine Modelle die großen ablösen und wo nicht
17. September 2026, 11 Min. Lesezeit
5-Layer Security-Modell für LLM-APIs: Input Validation, Authentication, Rate Limiting, Output Filtering, Monitoring. Mit Code-Beispielen und Tool-Empfehlungen.
Ein API-Aufruf an ChatGPT kostet Sie vielleicht 0,3 Cent. Ein kompromittierter API-Key kann Sie zehntausende Euro kosten, und das in wenigen Stunden. Sysdig dokumentierte im Mai 2024 unter dem Namen LLMjacking Angriffe mit gestohlenen Cloud-Credentials, bei denen dem Opfer Kosten von über 46.000 $ pro Tag entstehen können. Truffle Security fand in einem Common-Crawl-Archiv vom Dezember 2024 knapp 12.000 gültige Secrets, darunter AWS-Root-Keys und API-Keys. Dazu kommen Datenschutzverletzungen, wenn Kundendaten durch das LLM fließen, und Reputationsschäden, wenn Ihr Chatbot plötzlich Dinge sagt, die er nicht sagen sollte.
AI-APIs sind nicht wie normale APIs. Bei klassischen APIs gilt: Input A → Output B. Immer. Deterministisch. Bei LLM-APIs: Input A → Output B, C, D oder etwas völlig Unerwartetes. Und der Input selbst kann Code sein, auch wenn er wie harmloser Text aussieht.
Mit dem 5-Layer-Modell sichern Sie AI-APIs ab, von der Input-Validierung bis zum Monitoring. Die Code-Beispiele können Sie direkt einsetzen.
Warum reichen klassische API-Security-Maßnahmen nicht aus?
"Ignoriere vorherige Anweisungen" ist kein Text – es ist eine Anweisung, die das Modell ausführt. Das gleiche Prompt liefert unterschiedliche Antworten. Das macht klassisches Testing schwierig: Sie können nicht einfach Assert-Statements schreiben. Und Security-Validierung wird zum Moving Target.
| Durchlauf | Output |
|---|---|
| 1 | "Die Hauptstadt von Frankreich ist Paris." |
| 2 | "Paris ist die Hauptstadt Frankreichs." |
| 3 | "Frankreichs Hauptstadt: Paris." |
LLMs wurden auf Milliarden von Textdaten trainiert. Manchmal zeigen sie Verhaltensweisen, die niemand vorhergesehen hat und die sicherheitsrelevant sind:
Bevor Sie Security-Maßnahmen implementieren, sollten Sie die Threats kennen. Laut OWASP Top 10 for LLM Applications 2025 ist Prompt Injection die #1 Schwachstelle (LLM01). Sie betrifft praktisch jede Anwendung, die Nutzereingaben oder externe Inhalte an ein Modell weitergibt. Das klassische STRIDE-Modell lässt sich auf AI-Systeme anwenden, mit AI-spezifischen Beispielen.
| Threat | AI-Spezifisches Beispiel |
|---|---|
| Spoofing | Fake-Prompts von "vertrauenswürdigen" Quellen |
| Tampering | Prompt Injection, Training Data Poisoning |
| Repudiation | "Das habe ich nicht gefragt" (kein Logging) |
| Information Disclosure | System Prompt Leakage, PII in Outputs |
| Denial of Service | Token-Exhaustion, Infinite Loops |
| Elevation of Privilege | Jailbreaks, Guardrail-Bypasses |
Die Angriffsfläche von AI-APIs ist breiter als bei klassischen APIs. Angriffe können auf den Input, das Modell selbst, den Output oder die Infrastruktur zielen.
Wie sichern Sie Ihre AI-API konkret ab? Das 5-Layer-Modell geht von außen nach innen, vom Request bis zur Response.
Warum dieser Layer kritisch ist: Alles, was Nutzer eingeben, erreicht potenziell das LLM. Ohne Input-Validation ist Ihr System ein offenes Tor für Prompt Injection, PII-Leaks und Token-Exhaustion.
Was Sie validieren sollten:
class InputValidator:
def validate(self, user_input: str) -> ValidationResult:
checks = [
self.check_length,
self.check_pii,
self.check_injection_patterns,
self.check_encoding,
self.check_content_policy
]
for check in checks:
result = check(user_input)
if not result.passed:
return result
return ValidationResult(passed=True, sanitized=user_input)
Lange Inputs sind ein Risiko: Sie kosten mehr Tokens (= Geld), können DoS-Attacken ermöglichen und bieten mehr Raum für versteckte Injection-Payloads. Setzen Sie harte Limits.
def check_length(self, input: str) -> ValidationResult:
MAX_INPUT_LENGTH = 10000 # Tokens, nicht Zeichen
MAX_CHAR_LENGTH = 50000
if len(input) > MAX_CHAR_LENGTH:
return ValidationResult(
passed=False,
reason="Input too long"
)
return ValidationResult(passed=True)
Nutzer geben oft unbewusst persönliche Daten ein: E-Mail-Adressen, Telefonnummern, sogar Kreditkartendaten. Diese sollten nie das LLM erreichen, schon aus DSGVO-Gründen nicht.
import presidio_analyzer
def check_pii(self, input: str) -> ValidationResult:
analyzer = presidio_analyzer.AnalyzerEngine()
results = analyzer.analyze(
text=input,
language="de",
entities=["EMAIL_ADDRESS", "PHONE_NUMBER", "PERSON",
"CREDIT_CARD", "IBAN_CODE"]
)
if results:
# Option 1: Blockieren
return ValidationResult(passed=False, reason="PII detected")
# Option 2: Redaktieren (besser für UX)
# sanitized = anonymize(input, results)
# return ValidationResult(passed=True, sanitized=sanitized)
Prompt Injection ist der SQL-Injection-Moment für AI. Angreifer versuchen, Ihre System-Instruktionen zu überschreiben. Bekannte Patterns können Sie blocken, aber verlassen Sie sich nicht allein darauf.
INJECTION_PATTERNS = [
r"ignoriere?\s*(alle|vorherige|die)?\s*anweisung",
r"vergiss\s*(alles|deine|die)",
r"du\s+bist\s+(jetzt|ab\s+jetzt)",
r"system\s*prompt",
r"</?system>",
r"\[INST\]", # Llama-Format
r"###\s*(System|Instruction)",
]
def check_injection_patterns(self, input: str) -> ValidationResult:
for pattern in INJECTION_PATTERNS:
if re.search(pattern, input, re.IGNORECASE):
log_security_event("injection_attempt", pattern)
return ValidationResult(
passed=False,
reason="Suspicious pattern detected"
)
return ValidationResult(passed=True)
Warum dieser Layer kritisch ist: Ohne Authentication wissen Sie nicht, wer Ihre API nutzt. Ohne Authorization kann jeder alles, auch GPT-4o mit 128k Context. Bei aktuellen Preisen (Stand Dezember 2025: $2,50/1M Input, $10/1M Output) summiert sich das schnell auf dreistellige Beträge pro Stunde.
Klingt banal, wird aber oft falsch gemacht. Keys gehören nicht in Code oder Config-Files, sondern in einen Secrets Manager.
from fastapi import Depends, HTTPException, Security
from fastapi.security import APIKeyHeader
api_key_header = APIKeyHeader(name="X-API-Key")
async def verify_api_key(api_key: str = Security(api_key_header)):
# Gegen Secrets Manager validieren, nicht Hardcoded!
valid_keys = await secrets_manager.get_valid_keys()
if api_key not in valid_keys:
log_security_event("invalid_api_key", api_key[:8])
raise HTTPException(status_code=401, detail="Invalid API key")
return await get_key_metadata(api_key)
Nicht jeder Nutzer braucht Zugang zu jedem Modell. Ein Praktikant braucht kein GPT-4o, eine interne App kein Fine-Tuning. Definieren Sie Rollen mit klaren Berechtigungen.
class Permission(Enum):
GPT4O = "gpt4o"
GPT4O_MINI = "gpt4o_mini"
EMBEDDING = "embedding"
FINE_TUNE = "fine_tune"
AGENT = "agent"
ROLE_PERMISSIONS = {
"basic": [Permission.GPT4O_MINI, Permission.EMBEDDING],
"advanced": [Permission.GPT4O_MINI, Permission.GPT4O, Permission.EMBEDDING],
"admin": [Permission.GPT4O_MINI, Permission.GPT4O, Permission.EMBEDDING,
Permission.FINE_TUNE, Permission.AGENT],
}
async def check_permission(
key_meta: KeyMetadata,
required: Permission
) -> bool:
user_permissions = ROLE_PERMISSIONS.get(key_meta.role, [])
return required in user_permissions
Jeder Key sollte nur die Rechte haben, die er braucht. Scope, Modelle, Rate-Limits, Budget, IP-Ranges, Ablaufdatum: alles definiert.
# Key-Erstellung mit minimalem Scope
api_keys:
- id: key_prod_chat_001
role: basic
allowed_models: ["gpt-4o-mini"]
rate_limit: 100/minute
budget: 50/month
allowed_ips: ["10.0.0.0/8"]
expires: 2026-06-01
Mehr zum Thema API-Key-Management: Non-Human Identity Management
Warum dieser Layer kritisch ist: LLM-APIs sind teuer. Ein kompromittierter Key ohne Rate-Limit kann in Stunden fünfstellige Kosten verursachen. Außerdem schützt Rate-Limiting vor DoS und macht Credential-Stuffing unattraktiv.
Bei klassischen APIs reicht oft "60 Requests pro Minute". Bei LLMs ist das zu simpel: Ein Request mit 100k Tokens kostet 100x mehr als einer mit 1k Tokens. Sie brauchen Token-basiertes Limiting.
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
# Request-basiert (Basis-Schutz)
@app.post("/chat")
@limiter.limit("60/minute")
async def chat(request: Request):
...
# Token-basiert (kritisch bei LLMs!)
class TokenRateLimiter:
def __init__(self, max_tokens_per_minute: int):
self.max_tokens = max_tokens_per_minute
self.windows = {} # user_id -> deque of (timestamp, tokens)
async def check(self, user_id: str, estimated_tokens: int) -> bool:
window = self.windows.get(user_id, deque())
# Alte Einträge entfernen (> 1 Minute)
now = time.time()
while window and window[0][0] < now - 60:
window.popleft()
# Aktuelle Summe
current_tokens = sum(t for _, t in window)
if current_tokens + estimated_tokens > self.max_tokens:
return False
window.append((now, estimated_tokens))
self.windows[user_id] = window
return True
Rate-Limits schützen pro Minute, Budgets pro Monat. Definieren Sie für jeden Key oder User ein monatliches Budget und alertieren Sie frühzeitig.
class BudgetEnforcer:
async def check_budget(self, user_id: str, estimated_cost: float) -> bool:
user = await get_user(user_id)
current_spend = await get_current_month_spend(user_id)
if current_spend + estimated_cost > user.monthly_budget:
await notify_budget_exceeded(user_id)
return False
return True
async def record_spend(self, user_id: str, actual_cost: float):
await increment_spend(user_id, actual_cost)
# Alert bei 80%, 90%, 100%
current = await get_current_month_spend(user_id)
user = await get_user(user_id)
percentage = current / user.monthly_budget
if percentage >= 1.0:
await alert_budget_exceeded(user_id)
elif percentage >= 0.9:
await alert_budget_warning(user_id, 90)
elif percentage >= 0.8:
await alert_budget_warning(user_id, 80)
Warum dieser Layer kritisch ist: Input-Validation allein reicht nicht. LLMs können auch bei "sauberen" Inputs problematische Outputs generieren: PII aus dem Training, System-Prompt-Leaks oder Policy-Verletzungen.
Das LLM könnte persönliche Daten aus seinem Training oder aus dem Kontext in der Antwort wiedergeben. Scannen Sie Outputs genauso wie Inputs.
from presidio_anonymizer import AnonymizerEngine
def filter_pii_in_output(response: str) -> str:
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
results = analyzer.analyze(text=response, language="de")
if results:
log_security_event("pii_in_output", len(results))
anonymized = anonymizer.anonymize(
text=response,
analyzer_results=results
)
return anonymized.text
return response
Ein häufiges Angriffsziel: Nutzer versuchen, den System-Prompt zu extrahieren. Wenn das LLM beginnt, seine Instruktionen preiszugeben, sollten Sie die Response blocken.
SYSTEM_PROMPT_INDICATORS = [
"meine anweisungen sind",
"mir wurde gesagt",
"mein system prompt",
"ich wurde instruiert",
"meine richtlinien",
]
def check_system_prompt_leakage(response: str) -> bool:
lower_response = response.lower()
for indicator in SYSTEM_PROMPT_INDICATORS:
if indicator in lower_response:
log_security_event("potential_system_prompt_leak", indicator)
return True
return False
def filter_output(response: str) -> str:
if check_system_prompt_leakage(response):
return "Ich kann diese Anfrage nicht beantworten."
return filter_pii_in_output(response)
Für Hate Speech, Gewalt und andere Policy-Verletzungen bietet OpenAI eine kostenlose Moderation-API, inzwischen auch multimodal (Text + Bilder). Nutzen Sie sie, auch wenn Sie andere Modelle verwenden.
async def check_content_policy(response: str) -> ContentPolicyResult:
# Text-Moderation (kostenlos, basiert auf GPT-4o)
moderation = await openai.moderations.create(input=response)
if moderation.results[0].flagged:
categories = moderation.results[0].categories
log_security_event("content_policy_violation", categories)
return ContentPolicyResult(
passed=False,
categories=categories
)
return ContentPolicyResult(passed=True)
# Neu 2025: Auch Bilder können moderiert werden
async def check_image_policy(image_url: str) -> ContentPolicyResult:
moderation = await openai.moderations.create(
model="omni-moderation-latest",
input=[{"type": "image_url", "image_url": {"url": image_url}}]
)
return ContentPolicyResult(passed=not moderation.results[0].flagged)
Warum dieser Layer kritisch ist: Die anderen Layer sind präventiv. Monitoring ist detektiv: Es hilft Ihnen, Angriffe zu erkennen, die durch die anderen Layer geschlüpft sind, und gibt Ihnen die Daten für Forensik und Compliance.
Nicht den vollen Prompt, das wäre ein Datenschutzproblem. Aber genug Metadaten, um Anomalien zu erkennen und Incidents zu untersuchen.
@dataclass
class AIRequestLog:
timestamp: datetime
request_id: str
user_id: str
model: str
input_tokens: int
output_tokens: int
input_hash: str # Nicht den vollen Input loggen!
latency_ms: float
status: str
cost: float
flagged: bool
flags: List[str] # PII, injection_attempt, etc.
async def log_request(log: AIRequestLog):
await siem_client.send(log.to_dict()) # An SIEM senden
await billing_service.record(log) # Für Billing
await analytics_service.record(log) # Für Analytics
Statische Regeln fangen bekannte Patterns. Anomaly Detection fängt unbekannte. Bauen Sie Baselines pro User auf und alertieren Sie bei Abweichungen.
class AnomalyDetector:
def __init__(self):
self.baselines = {} # user_id -> BaselineStats
async def check(self, user_id: str, request: AIRequest) -> List[Anomaly]:
anomalies = []
baseline = self.baselines.get(user_id)
if not baseline:
return [] # Erste Requests, noch keine Baseline
# Ungewöhnliche Zeit
if not baseline.is_typical_hour(request.timestamp.hour):
anomalies.append(Anomaly("unusual_time", severity="medium"))
# Ungewöhnliches Volume
if request.tokens > baseline.avg_tokens * 3:
anomalies.append(Anomaly("high_token_count", severity="medium"))
# Ungewöhnliches Model
if request.model not in baseline.typical_models:
anomalies.append(Anomaly("unusual_model", severity="low"))
# Ungewöhnliche IP
if request.ip not in baseline.known_ips:
anomalies.append(Anomaly("new_ip", severity="high"))
return anomalies
Definieren Sie klare Alert-Rules mit Severity und Action. Wer wird wann benachrichtigt? Was passiert automatisch?
alerts:
- name: injection_attempt_detected
condition: flags contains "injection_attempt"
severity: high
action: notify_security_team
- name: pii_in_output
condition: flags contains "pii_detected"
severity: medium
action: notify_privacy_team
- name: unusual_activity
condition: anomaly_score > 0.8
severity: medium
action: notify_security_team
- name: budget_exceeded
condition: monthly_spend > budget
severity: low
action: disable_key, notify_user
Sie müssen nicht alles selbst bauen. Diese Open-Source-Tools und Frameworks decken wesentliche Teile des 5-Layer-Modells ab. Stand: Dezember 2025.
Open-Source-Bibliothek für Input- und Output-Scanning. Deckt Prompt Injection, Toxicity, PII und mehr ab. Aktiv gepflegt (letztes Update November 2025).
from llm_guard import scan_prompt, scan_output
from llm_guard.input_scanners import PromptInjection, Toxicity
from llm_guard.output_scanners import Sensitive, Relevance
input_scanners = [PromptInjection(), Toxicity()]
output_scanners = [Sensitive(), Relevance()]
# Input scannen
sanitized_prompt, results, is_valid = scan_prompt(
input_scanners, user_prompt
)
# Output scannen
sanitized_output, results, is_valid = scan_output(
output_scanners, user_prompt, llm_response
)
NVIDIA's Framework für programmierbare Conversation-Guardrails. Version 0.18.0 (November 2025) unterstützt jetzt auch Reasoning-Traces (BotThinking Events), LangGraph-Integration und Multi-Agent-Workflows.
from nemoguardrails import RailsConfig, LLMRails
config = RailsConfig.from_path("./config")
rails = LLMRails(config)
# Guardrails automatisch angewendet
response = rails.generate(messages=[{"role": "user", "content": prompt}])
Wichtig: Python 3.10+ erforderlich (Support für 3.9 wurde im Oktober 2025 entfernt).
Der Goldstandard für PII-Detection und Anonymisierung. Unterstützt Deutsch und viele andere Sprachen. Für managed Services: Azure AI Language PII Detection bietet ähnliche Funktionalität als Cloud-Service.
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
# PII finden
results = analyzer.analyze(
text=text,
entities=["PERSON", "EMAIL_ADDRESS", "PHONE_NUMBER"],
language="de"
)
# Anonymisieren
anonymized = anonymizer.anonymize(text=text, analyzer_results=results)
Die großen Cloud-Provider bieten inzwischen native Guardrails:
Nicht alle Layer müssen am ersten Tag implementiert sein. Priorisieren Sie risikoorientiert:
Woche 1: Input Validation + Authentication. Ohne diese beiden ist alles andere wertlos. Ein LLM ohne Input-Validation ist ein offenes System für Prompt Injection. Ohne Authentication wissen Sie nicht einmal, wer angreift.
Woche 2: Rate Limiting + Budget-Controls. Kosten-Explosionen durch Missbrauch sind einer der häufigsten realen Incidents bei LLM-APIs. Setzen Sie Limits, bevor Sie live gehen, nicht nachdem die erste Rechnung kommt.
Woche 3-4: Output Filtering + Monitoring. Output-Filter schützen vor PII-Leaks und System-Prompt-Leakage. Monitoring gibt Ihnen die Visibility, um Anomalien zu erkennen, bevor sie zu Incidents werden.
Die Code-Beispiele in diesem Artikel sind Startpunkte. Passen Sie sie an Ihre Architektur an, aber implementieren Sie alle 5 Layer.
17. September 2026, 11 Min. Lesezeit
7. Dezember 2025, 14 Min. Lesezeit
30. November 2025, 14 Min. Lesezeit
Für Vorträge, Interviews und fachlichen Austausch erreichen Sie mich direkt. Projekte und Beratung laufen über meinen Arbeitgeber ADVISORI, den Kontakt stelle ich gern her.