AI-Ready Websites haben oeffentliche API-Endpoints. Das ist der ganze Punkt -- KI-Agenten sollen Services nutzen koennen, ohne dass ein Mensch eingreift. Aber oeffentliche Endpoints bedeuten auch: Jeder kann sie aufrufen. Nicht nur hilfreiche KI-Agenten, sondern auch Bots, Scraper und Angreifer.
Wer eine AI-Ready Website baut und Security nicht von Tag 1 mitdenkt, baut ein offenes Tor.
Das Problem: Oeffentlich heisst angreifbar
Eine klassische Website hat ein Kontaktformular. Spam-Schutz? reCAPTCHA, Honeypot-Felder, vielleicht ein Rate Limit. Das funktioniert, weil Menschen Formulare ausfuellen -- und CAPTCHAs koennen die meisten Bots nicht loesen.
Eine AI-Ready Website hat API-Endpoints wie /api/v1/quote oder /api/v1/consultation. Diese Endpoints sind designed fuer maschinelle Nutzung. Ein CAPTCHA wuerde den gesamten Zweck zerstoeren -- KI-Agenten sollen ja gerade maschinell darauf zugreifen.
Das erzeugt ein Dilemma: Die Tuer muss offen sein fuer legitime Agents, aber geschlossen fuer Missbrauch. Die Loesung ist nicht ein einzelner Mechanismus, sondern mehrere Schichten.
Schicht 1: Input-Validierung mit Zod
Die erste Verteidigungslinie ist die einfachste: Pruefe, ob die eingehenden Daten gueltig sind, bevor sie irgendetwas ausloesen.
Zod ist eine TypeScript-Validierungsbibliothek, die Daten gegen ein definiertes Schema prueft. Keine Magie, keine KI -- reine Strukturpruefung.
Warum nicht einfach if-Statements?
Koennte man. Aber bei komplexeren Datenstrukturen wird das schnell unuebersichtlich und fehleranfaellig. Zod erzwingt eine klare Struktur:
import { z } from "zod";
const quoteSchema = z.object({
projectType: z.enum(["website", "webshop", "webapp", "redesign"]),
pages: z.string().optional(),
features: z.string().optional(),
});
// In der API Route:
const parsed = quoteSchema.safeParse(body);
if (!parsed.success) {
return ApiError.validation(
"Ungueltige Eingabedaten",
parsed.error.issues
);
}
Was Zod konkret verhindert
- Fehlende Pflichtfelder: Ein Request ohne
projectTypewird sofort abgelehnt - Falsche Typen: Ein
pages-Wert vontruestatt einem String wird erkannt - Unerwartete Werte: Ein
projectTypevon"hacking"wird durch das Enum blockiert - Injection-Versuche: SQL- oder NoSQL-Injection ueber manipulierte Felder wird durch die strenge Typisierung erschwert
Das klingt basic -- und das ist es auch. Aber die Mehrheit der Sicherheitslucken entsteht nicht durch raffinierte Angriffe, sondern durch fehlende Eingabevalidierung.
Praxis: Beratungsanfrage validieren
const consultationSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
phone: z.string().optional(),
topic: z.string().min(5).max(500),
});
Dieser Schema-Check stellt sicher:
- Name hat mindestens 2 und maximal 100 Zeichen (keine leeren Strings, keine Roman-Laenge)
- Email ist ein gueltiges Email-Format (keine Freitext-Injection)
- Topic hat 5-500 Zeichen (kein leerer Submit, kein 10MB-Payload)
Schicht 2: Rate Limiting
Validierung schuetzt vor falschen Daten. Rate Limiting schuetzt vor zu vielen Anfragen.
Wie Rate Limiting funktioniert
Das Prinzip ist einfach: Zaehle, wie viele Anfragen eine IP-Adresse innerhalb eines Zeitfensters stellt. Ueberschreitet sie das Limit, bekommt sie einen 429 Too Many Requests Status zurueck.
IP 192.168.1.1:
Zeitfenster: 60 Sekunden
Limit: 60 Anfragen
Aktuell: 47
→ Erlaubt
IP 10.0.0.5:
Zeitfenster: 60 Sekunden
Limit: 60 Anfragen
Aktuell: 61
→ Blockiert (Retry-After: 23s)
Unterschiedliche Limits fuer unterschiedliche Endpoints
Nicht jeder Endpoint braucht das gleiche Limit:
| Endpoint-Typ | Limit | Grund |
|---|---|---|
| GET-Endpoints (Portfolio, Services) | 60/Minute pro IP | Lesen ist guenstig, hoehere Toleranz |
| POST-Endpoints (Quote, Consultation) | 10/Minute pro IP | Schreiben ist teuer, engere Kontrolle |
| Externe-Call-Endpoints (AI-Ready Check) | 10/Minute pro IP | Machen HTTP-Calls nach aussen, Missbrauchsrisiko hoch |
Warum der Unterschied? Ein GET-Endpoint liest Daten aus der Datenbank -- das ist schnell und guenstig. Ein POST-Endpoint schreibt Daten, sendet moeglicherweise E-Mails oder loest andere Aktionen aus. Und ein Endpoint, der externe Websites aufruft (wie unser AI-Ready Check), koennte fuer DDoS-Attacken auf Dritte missbraucht werden.
Die Response bei Rate Limiting
Wenn ein Limit erreicht ist, erhaelt der Client eine klare Antwort:
{
"error": "Rate limit exceeded. Max 60 requests per minute.",
"retryAfterMs": 23000
}
Plus HTTP-Header, die dem Client (oder Agent) sagen, wo er steht:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1739654400
Ein gut gebauter KI-Agent liest diese Header und wartet automatisch. Ein Angreifer bekommt zumindest eine Bremse.
Schicht 3: Error Sanitization
Wenn etwas schiefgeht -- und es geht immer irgendwann etwas schief -- darf die Fehlermeldung keine internen Details preisgeben.
Was ein Angreifer aus Fehlermeldungen lernt
Ein unsanitisierter Fehler koennte so aussehen:
{
"error": "PrismaClientKnownRequestError: Invalid `prisma.client.create()` invocation in /home/user/app/lib/db.ts:47:3",
"stack": "at Object.create (/home/user/node_modules/@prisma/client/runtime/library.js:123:45)"
}
Was verraet das? Den ORM (Prisma), den Dateipfad, die Zeile im Code, die Node.js-Version. Ein Angreifer weiss jetzt, wo er suchen muss.
Wie wir Fehler zurueckgeben
Unsere API gibt immer dasselbe Format zurueck:
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
}
}
Im Development-Modus sehen Entwickler die vollstaendige Fehlermeldung. In Production sieht jeder Aufrufer nur "Internal server error". Kein Stack Trace, kein Dateipfad, kein ORM-Name.
Die Error-Codes
Wir verwenden sechs definierte Error-Codes:
| Code | HTTP Status | Bedeutung |
|---|---|---|
UNAUTHORIZED | 401 | API-Key fehlt oder ungueltig |
FORBIDDEN | 403 | Key hat nicht die noetige Berechtigung |
RATE_LIMITED | 429 | Zu viele Anfragen |
VALIDATION_ERROR | 400 | Ungueltige Eingabedaten |
NOT_FOUND | 404 | Ressource nicht gefunden |
INTERNAL_ERROR | 500 | Serverfehler (keine Details) |
Ein KI-Agent kann diese Codes lesen und darauf reagieren: Bei 429 warten, bei 400 die Anfrage korrigieren, bei 401 sich authentifizieren.
Schicht 4: CORS-Konfiguration
CORS (Cross-Origin Resource Sharing) kontrolliert, wer von wo auf die API zugreifen darf.
Fuer AI-Ready Discovery-Endpoints (wie agents.json) muss CORS offen sein -- KI-Agenten kommen von ueberall. Aber es gibt Nuancen:
Discovery Endpoints (GET only):
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
→ Jeder darf lesen, aber nur lesen.
API Endpoints:
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
→ Voller Zugriff, aber nur mit erlaubten Headern.
Die OPTIONS-Methode ist fuer Preflight-Requests -- Browser fragen erst "Darf ich?", bevor sie den eigentlichen Request senden. Diese Preflight-Response cachen wir fuer 24 Stunden (Access-Control-Max-Age: 86400), um unnoetige Requests zu vermeiden.
Schicht 5: Was nicht exponiert wird
Genauso wichtig wie die Absicherung oeffentlicher Endpoints ist die Frage: Was bleibt privat?
Bei uns sind das:
- Interne MCP-Tools (242 Tools fuer die Website-Entwicklung -- nicht oeffentlich)
- Datenbank-IDs und -Strukturen (keine Prisma-IDs in API-Responses)
- Authentifizierungs-Tokens (nie in Logs oder Responses)
- Server-Konfiguration (keine Versionsnummern, keine Pfade)
- Persoenliche Nutzerdaten (DSGVO sowieso, aber auch API-technisch isoliert)
Das klingt selbstverstaendlich, ist es aber nicht. Viele APIs geben Datenbank-IDs zurueck ("id": 47), aus denen sich die Gesamtzahl der Datensaetze ableiten laesst. Oder sie legen Stack Traces in Logs ab, die ueber Error-Tracking-Tools oeffentlich lesbar sind.
Auth-Konzepte: Heute und morgen
Was wir heute haben
Fuer die oeffentlichen Business-Endpoints (Portfolio, Services, Quote) gibt es bewusst keine Authentifizierung. Der Grund: Diese Endpoints liefern Informationen, die auch auf der Website oeffentlich sichtbar sind. Ein Preiskalkulator ist kein Geheimnis.
Fuer erweiterte Endpoints (Animations-API, Analytics) nutzen wir API-Keys mit Scoped Permissions:
Bearer sk_live_abc123...
Scopes: animations:read, animations:generate
Rate Limit: 100/min (konfigurierbar pro Key)
Was die Zukunft bringt
Wenn A2A und aehnliche Protokolle breiter adoptiert werden, wird die Frage der Agent-Authentifizierung zentral. Wie weist ein KI-Agent nach, dass er im Auftrag eines bestimmten Nutzers handelt?
Moegliche Ansaetze:
- OAuth 2.0 Token Relay: Der Agent erhaelt ein Token vom Nutzer und leitet es weiter
- Agent Identity Certificates: Digitale Zertifikate fuer verifizierte Agents
- DID (Decentralized Identifiers): Selbst-souveraene Identitaeten fuer Agents
Stand heute ist keiner dieser Ansaetze standardisiert fuer Agent-Kommunikation. Aber die Grundlagen (OAuth, Zertifikate) existieren -- es fehlt die Standardisierung im A2A-Kontext.
Die goldene Regel: Security ist kein Feature, es ist eine Voraussetzung
Der haeufigste Fehler bei AI-Ready Websites: Erst die Endpoints bauen, dann "spaeter" absichern. "Spaeter" kommt erfahrungsgemaess nie -- oder erst nach dem ersten Vorfall.
Unsere Checkliste fuer jeden neuen Endpoint
☐ Zod-Schema definiert?
☐ Rate Limit konfiguriert (GET: 60/min, POST: 10/min)?
☐ Error Responses sanitized (keine Stack Traces)?
☐ CORS-Header gesetzt?
☐ Keine Datenbank-IDs in der Response?
☐ Keine persoenlichen Daten ohne Auth?
☐ Logging ohne sensitive Daten?
Diese Checkliste ist kein Overhead. Sie ist der Unterschied zwischen einem Endpoint, der nuetzlich ist, und einem, der zum Problem wird.
Zusammenfassung
| Schicht | Schuetzt vor | Mechanismus |
|---|---|---|
| Input-Validierung | Falschen/manipulierten Daten | Zod-Schemas mit strikten Typen |
| Rate Limiting | Ueberlastung und Brute Force | IP-basierte Zaehler mit Zeitfenster |
| Error Sanitization | Informationsleck | Generische Fehlermeldungen in Production |
| CORS | Unerlaubtem Cross-Origin-Zugriff | Header-basierte Zugriffskontrolle |
| Auth (API Keys) | Unauthorisiertem Zugriff auf Premium-Endpoints | Bearer Tokens mit Scoped Permissions |
| Non-Exposure | Versehentlicher Datenpreisgabe | Bewusste Entscheidung, was privat bleibt |
Security fuer AI-Ready Websites ist kein Spezialthema. Es ist dasselbe Grundprinzip wie bei jeder API -- Validierung, Rate Limiting, saubere Fehlerbehandlung. Der Unterschied ist, dass die Endpoints designed sind fuer maschinellen Zugriff, was die Angriffsflaeche von Tag 1 groesser macht.
Wer das von Anfang an mitdenkt, hat kein Problem. Wer es nachholt, hat Arbeit.
