👹

プロンプトに頼らないプロンプトインジェクション対策を考えてみる

2023/03/10に公開

プロンプトインジェクションとても楽しいですね!
最近のブームは語尾ににゃあ/にゃんとつけて文章を可愛くするのにハマっています。

ところで皆さんこちらの記事はもう読まれましたか?
https://qiita.com/sakasegawa/items/09d9f6a485108f5a618a
プロンプトインジェクション対策についていろいろと知見が入っていてとても良い記事なのでお読みください。

こういったものは防御側の知見を貯めるのはとても大事なことなので僕も日々いろんな防御策を試しています。
違う。そうじゃない。
しかし、いろいろ試しているところ、良くも悪くも指示や命令というものはとても強くなかなか完全な防御をすることは難しく感じます。

そこでサービスなどにLLMを組み込むさいに、プロンプトインジェクションを起こさせない、または起きても意味がない状況を作ることを考えてみましょう。

1. ユーザーの入力した値を使わない

もっとも簡単な方法はユーザーの入力した値を使わないことです。
ユーザーは入力できないのでプロンプトインジェクションは起き得ません。

例えば、システムが発行するユーザーの行動イベントなどを元にLLMに入力するようなサービスを作る場合にはこういった手法が使えそうですね。

2. バリデーションされた値のみを使う

次に簡単なのはシステムでバリデーションした値だけを使うことです。
これもユーザーは自由に入力できないのでプロンプトインジェクションを起こすことはできません。

例えば、占いサイトや性格診断系のサイトなどでは必要な入力は性別、生年月日、血液型など決まった入力があれば良いのでそういった場合にはこの手法が使えそうです。

3. 過去の文脈を保持しない/そのユーザーの文脈だけを入れる

ChatGPT APIでは文脈を保持するために過去のやりとりを保管し、API実行時にそれを含めることで文脈の維持を行いますが、ここでミスをすれば他者の情報がプロンプトインジェクションで流出させることができます。
そのため、文脈保持が不要なケースでは過去のやりとりは含めず、もし必要なら適切に過去のやりとりを扱いましょう。

何を当たり前なと思われるかもしれませんが、みんなが確実にこれをできるなら事故は起きないんだ。

4. プロンプトに秘匿すべき情報を含めない

基本的にプロンプトに含められた情報はすべて引き出せると考えた方が現時点では良さそうだと考えます。
そのため、そのユーザーが知ってはいけない情報をプロンプトに含めないというのも一つの対策になるかと思います。

例えば、アクセスキーを必要するコードを生成して実行をするケースなどの場合、プロンプトにアクセスキーを含めたくなりますが、代替文字列にするように指示を行い、その結果に対してリプレイスでアクセスキーを埋め込むなんていうのもわかりやすい例かと思います。
(僕は某サービスのAPIを叩くコードの生成でこれをやりそうになりました)

5. LLMが生成した文字列を信用せずに適切なセキュリティ対策を行う

例えばLLMが生成した文字列をRDBMSに保存するとには必ずプレースホルダーを使いましょう。
HTMLで表示する場合にはXSSできない方式で埋め込みましょう。
この辺りは特に特別なことではなくサービスを作っていれば当たり前に行うことです。

LLMが生成した文字列を信用せずに適切に扱うことで、他のインジェクションなどを狙ったプロンプトインジェクションは無効化することができます。

6. 出力フォーマットを指定し、そのフォーマットになってなければエラーにする

これは現時点のLLMの精度では悩ましいですが、一定のフォーマットで回答させることで想定外の結果ならエラーにするというのも効果はあると思います。
例えば冒頭の画像のようにtrue/falseで返せとかなり限定的な出力にすることで、プロンプトインジェクションで壊されないようにできます。

ただし、精度問題はあるので通常のプロンプトでも同様の問題が起きえるのは悩ましいですね。

7. UIにプロンプトを表示する

これは一長一短な気もしますが、例えばLLMが生成した文章を公開して共有するようなサービスでは、プロンプトを表示することでこのサービスではこういった差別的な発言を公開しているといった風評被害を防ぐことができると思います。
ただし、逆におもちゃにされる可能性もあるため一概にこの手法を使うべきだとも言い難いです。この辺はサービス設計としてどうバランスを取るか悩ましいですね。

8. 限定的な範囲でしかLLMの生成結果を見せない

6の対案としては見せる範囲を限定化することで、プロンプトインジェクションで差別的な発言が出てしまっても影響を限定することができます。
例えばSlackのような見知った人間だけのコミュニティなどでは風評被害的なものはそこまで気にする必要はないように思えます。(またチャットベースの場合は6のプロンプトがチャットに残るし)

また、壊れることで不利益が攻撃者にしか起きないというのも一つの対策だとは思います。
例えばChatGPTのWeb UIでプロンプトインジェクションを行なったとしても、他者に迷惑が出ないためサービスとしては許容できると考えることもできます。

こう考えるとサービス特性によってプロンプトインジェクションに対してどこまで許容するかというものが変わってくるので面白いですね。

9. LLMの生成結果を人間が検査する

確実性やスケーラビリティは下がりますが、適切な結果になっているか人間が検査するというのも手法としてはあるかと思います。
実際にこれを行うさいには、何かしらで生成結果を点数にし、一定の閾値を超えた場合のみ人間がチェックするという形になるかとは思います。(何かしらはあんまり思いついてない)

おわりに

ざっと思いつくものをまとめてみました。
こうまとめてみると壊させない、壊れても問題ないようにするというのはサービスにLLMを導入する1つの考え方として必要なことかもしれないですね。

Discussion