Chatbot auf Bedrock absichern: Defense in Depth statt einer einzelnen Schutzschicht
Ein öffentlicher LLM-Chatbot braucht mehrere unabhängige Schutzschichten: Prompt-Härtung, Guardrail, Rate-Limit ohne WAF, harte Kostenbremse und EU-Routing. Was ich gebaut, gemessen und dabei gelernt habe.
Auf chnet.solutions beantwortet ein Chatbot Fragen zu meinem Profil und meinen Leistungen. Dahinter steckt ein kleines Claude-Modell auf Amazon Bedrock. Interessant ist nicht der Bot, sondern die Frage, die sich bei jedem öffentlichen LLM-Endpunkt stellt: Wie verhindere ich, dass daraus eine kostenlose Allzweck-KI auf meiner AWS-Rechnung wird? Ein Anwendungsfall, kein Showcase: Das Muster lässt sich auf jeden FAQ-, Support- oder Produktberater-Bot übertragen.
Hypothese
Keine einzelne Maßnahme hält einen öffentlichen LLM-Chatbot zuverlässig im Thema und im Budget. Mehrere unabhängige Schichten, von denen jede für sich umgehbar ist, sollten zusammen tragen: Ein Angriff, der den System-Prompt aushebelt, scheitert an der Guardrail; ein Flood, der die Guardrail gar nicht braucht, scheitert am Rate-Limit; und wenn alles versagt, zieht die Kostenbremse den Stecker.
Gemessen wird das an zwei Fragen: Beantwortet der Bot legitime Fragen und lehnt er alles andere mit einem definierten Satz ab? Und bleibt die Kostenseite auch im Missbrauchsfall nach oben begrenzt?
Aufbau
Der Stack ist bewusst klein: statische Website, HTTP API (API Gateway v2), eine Lambda-Funktion, zwei DynamoDB-Tabellen, Bedrock, alles in AWS CDK. Die Schutzschichten liegen in dieser Reihenfolge:
- Gehärteter System-Prompt mit Refusal-Anker. Der Prompt legt nicht nur fest, was der Bot beantwortet, sondern ausdrücklich, was nicht – mit In- und Out-of-Scope-Beispielen und einem festen Ablehnungssatz („Diese Frage liegt außerhalb meines Themengebiets …“). Dieser feste Satz ist der eigentliche Trick: Er macht Ablehnungen maschinell erkennbar und damit testbar.
- Bedrock Guardrail. Vier verbotene Themen (allgemeine Programmierhilfe, Allgemeinwissen, fremde Personen und Firmen, Rollenspiele), ein Prompt-Attack-Filter, Inhaltsfilter und eine kurze Wortliste mit klassischen Jailbreak-Phrasen. Sie prüft Ein- und Ausgabe, ohne eigenen Code.
- Vorfilter vor Bedrock. Eine einfache Heuristik fängt Ping-Floods, reine Satzzeichen und wiederholte Fast-Duplikate ab und antwortet mit einem festen Hinweis, ganz ohne Modellaufruf.
- Konversationsgrenzen. Höchstens 12 Turns pro Gespräch, höchstens 400 Tokens pro Antwort, der Verlauf wird bei 8 000 Tokens gekappt. Der System-Prompt steht bei jedem Turn vorne, damit ein langer Verlauf die Rolle nicht verwässert.
- IP-Rate-Limit ohne WAF. Ein festes Kontingent pro IP und Zeitfenster, umgesetzt als atomarer Zähler in DynamoDB mit TTL. Dazu eine feste Obergrenze von 10 gleichzeitigen Lambda-Ausführungen.
- Budget-Kette mit Auto-Disable. Ein AWS Budget auf die Bedrock-Kosten warnt per Mail bei 50, 80 und 100 Prozent der Prognose. Bei 100 Prozent der tatsächlichen Kosten löst es über SNS eine kleine Lambda-Funktion aus, die die Concurrency des Chat-Handlers auf 0 setzt. Sie darf nur genau das, und das Wiedereinschalten ist bewusst manuell.
- EU-Datenresidenz. Bedrock wird über ein EU-Cross-Region-Inferenzprofil aufgerufen, das nur zwischen europäischen Regionen routet. Gesprächsprotokolle liegen in der EU-Heimatregion und werden nach 90 Tagen automatisch gelöscht.
Bewusste Abkürzungen: kein eigenes Klassifikationsmodell vor dem Hauptmodell, kein Fine-Tuning, kein Streaming. Concurrency-Grenze und Budget-Kette sind das Netz unter allen anderen Schichten.
Messung
Gemessen wird mit einer Eval-Suite gegen den deployten Endpunkt – wie ein Unit-Test, nur mit echtem Modellaufruf. Sie umfasst inzwischen 84 Fälle in 14 Gruppen: legitime Fragen, einfache und „getarnte“ Off-Topic-Fragen, Prompt-Injection, Kontext-Drift über mehrere Turns, Spam, Lead-Anfragen und Rückfragen nach einer Ablehnung. Bewertet wird über den Refusal-Anker: Ablehnung erwartet und Satz vorhanden, oder Sachantwort erwartet und Satz nicht vorhanden.
Der jüngste Volllauf (27. Oktober 2026, 84 Fälle) ergab 73 von 84 bestanden, also 86,9 Prozent bei einem Ziel von 95 Prozent; im Mai 2026 waren es 61 von 73 (83,6 Prozent). Alle 11 Fehlschläge liegen bei legitimen Fragen und Lead-Abläufen: Der Bot lehnte einfache Skill-Fragen ab, schloss Lead-Anfragen nicht wie vorgesehen ab oder wiederholte nach einer Klarstellung seinen Ablehnungssatz. Kein Fehlschlag betraf Off-Topic-, Injection-, Kontext-Drift- oder Spam-Fälle. Die Lücke ist ehrliches Signal, kein Messfehler – und das war die erste Lektion.
Lessons learned
- Der Testläufer selbst war das Leck. Eine frühere Version wertete HTTP-Fehler mit leerem Body als Sachantwort. Unter Last „bestand“ der Bot so Fälle, die er nie beantwortet hatte. Seit der Läufer bei 4xx/5xx hart scheitert, sind die Zahlen niedriger und belastbar.
- Zu scharfe Filter blockieren echte Interessenten. Der Prompt-Attack-Filter auf höchster Stufe stufte alle 4 getesteten Du-Anreden („kannst du AWS?“) als Angriff ein; die Antwort kam leer zurück. Eine Stufe tiefer erkennt er Jailbreaks weiterhin, lässt normale Anrede aber durch. Ähnlich bei den verbotenen Themen: Eine zu breite Definition erklärte Fragen zu meinen eigenen Skills für off-topic. Guardrail-Themen kennen keine Negativbeispiele, der einzige Hebel ist die Definition selbst – mit hartem Zeichenlimit.
- Zu enger Scope verliert Leads. Anfragen wie „ich würde gern meine Website auf AWS hosten“ wurden anfangs abgelehnt. Lead-Anfragen sind jetzt eine eigene In-Scope-Kategorie, und nach einer Klarstellung darf der Bot den Ablehnungssatz nicht wiederholen.
- WAF passt nicht an jede API. AWS WAF lässt sich nicht an eine API Gateway HTTP API v2 hängen, nur an REST-APIs, CloudFront und einige andere Ziele. Daher das Rate-Limit in der Lambda-Funktion.
- Budget Actions können keine Lambda drosseln. Sie kennen IAM-, SCP- und SSM-Aktionen, aber keine Concurrency-Änderung. Daher die Kette Budget → SNS → Lambda.
- Bedrock-Zugang ist ein Marketplace-Vorgang. Anthropic-Modelle erfordern ein Abonnement über AWS Marketplace plus ein Use-Case-Formular. Der Klick muss auf der Marketplace-Produktseite passieren, nicht in der Bedrock-Konsole. Danach braucht die Freigabe einige Minuten, bis sie in allen EU-Regionen des Inferenzprofils angekommen ist – bis dahin gibt es sporadisch AccessDenied.
- IAM muss alle Routing-Regionen kennen. Die Berechtigung wird gegen das Modell in der tatsächlich gerouteten Region geprüft. Fehlt eine der Profil-Regionen in der Policy, scheitern Anfragen zufällig.
Fazit
Die Hypothese ist bestätigt, mit Einschränkung. Off-Topic- und Injection-Fälle hat die Eval durchgehend abgewehrt. Die Kostenseite ist durch Concurrency-Grenze, Rate-Limit und Budget-Kette konstruktiv begrenzt – begründet, aber nicht gemessen; einen Auslösefall der Budget-Kette habe ich nicht dokumentiert. Die offene Baustelle sind Fehlablehnungen legitimer Fragen: Sicherheitsschichten erzeugen Reibung, und die trifft zuerst die Besucher, für die der Bot gebaut ist.
Für Kundenprojekte nehme ich mit: Die Eval-Suite mit eindeutigem Refusal-Anker ist so wichtig wie die Schutzschichten selbst, weil nur sie zeigt, ob eine Verschärfung Angriffe oder Kunden abwehrt. Die Kostenbremse gehört ab dem ersten Deploy dazu. Und Plattformgrenzen wie WAF bei HTTP APIs oder die Marketplace-Freischaltung prüft man besser in der Planung als beim Deploy.
Stack: Amazon Bedrock · Claude · Bedrock Guardrails · AWS Lambda · API Gateway HTTP API · DynamoDB · AWS Budgets · AWS CDK