背景
先日、Claude Codeはプロンプトインジェクションで.envを漏洩させるのか?検証してみたという記事を読みました。Claude Codeを悪用したプロンプトインジェクションで.envの内容が漏洩し得ることを実際に検証した記事です。
また、XではGoogle広告のMCCアカウント乗っ取り被害が報告されています。広告業界でエンジニアをしている私にとって、これは他人事ではありません。
正直なところ、自分は「permissions.denyで.envの読み取りをブロックしておけば問題ないだろ」くらいに思っていました。しかし、AI コーディングツールに API キーを盗み読みさせないための多層キー管理ガイドを読んで、denyルールだけでは全然足りないことを知り、自分の対策不足を痛感しました。
この記事では、そこから自分なりに何ができるかを考えて実際に取り組んだことをまとめています。
denyルールだけでは認証情報を守れない
Claude Codeにはpermissions.denyという設定があり、特定のファイルへのアクセスをブロックできます。
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(**/.env*)"
]
}
}
一見これで.envファイルを読めなくなるように思えますが、実はこれだけでは不十分です。理由は大きく2つあります。
1. 設定自体にバグがある可能性
The Registerの報道によると、Claude Codeは.claudeignoreに明記しても.envを読み込むケースが確認されています。denyルールも同様に、意図した通りに機能しない可能性があります。設定に依存した防御は、その設定が確実に動作する保証がなければ脆弱です。
2. 「静止時」と「実行時」は別の脅威
denyルールが防げるのは、あくまで**ファイルの読み取り(静止時のシークレット)**です。しかし、.envに書かれたAPIキーは、アプリケーション実行時に環境変数としてプロセスに注入されます。
つまり、Claude Codeがprintenvやenvコマンドを実行すれば、ファイルを読まなくても環境変数から認証情報を取得できてしまいます。
# denyルールをすり抜ける例
printenv OPENAI_API_KEY
# => sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
これは「secrets at rest(静止時)」と「secrets at runtime(実行時)」という異なる脅威モデルの問題です。denyルールは前者にしか対応できません。
認証情報を守るための取り組みには、個人でできることとチームで行うことがあります。
個人でできること:PCから平文のシークレットを排除する
まずは自分のPC上に平文のシークレットを置かないことが基本です。.envファイルにAPIキーをベタ書きしている状態をやめて、シークレットマネージャーから実行時に取得する構成に変えます。
1Passwordを試した結果
参照記事では1Password CLIを使った構成が紹介されています。実際に試してみましたが、いくつか気になる点がありました。
- 月額5ドルの有料サービスである
- 機能は充実しているが、チーム全員が環境を整えるのが手間
- セキュリティがしっかりしている反面、CLIの認証が30分で切れるため、開発中に再認証を求められることがある
開発のセキュリティ保持のためだけに1Passwordを契約するのは、少しオーバースペックに感じました。
Apple Keychainで十分だった
結論として、macOSの標準機能であるApple Keychainで同じことができます。
- 追加費用なし
- 特別なツールのインストール不要
- コマンドでシークレットの保存・参照ができる
- 開発PCがMacで統一されていれば、コマンドの共有だけでチームメンバーへの展開が完了する
direnv + Apple Keychainのセットアップ
環境変数をディレクトリごとに管理するために、direnvを組み合わせます。
direnvのインストール
brew install direnv
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
source ~/.zshrc
Keychainにシークレットを保存する
security add-generic-password -a "$USER" -s TEST_KEY -w 'test-key'
保存したシークレットを参照する
security find-generic-password -a "$USER" -s TEST_KEY -w
.envrcからKeychainを参照する
export TEST_KEY="$(security find-generic-password -a "$USER" -s TEST_KEY -w)"
direnvを有効化する
direnv allow
これで、プロジェクトディレクトリに入ったときだけ環境変数が自動的にセットされ、.envファイルに平文のキーを書く必要がなくなります。
チームで行うこと
個人の対策でディスク上の平文は排除できますが、1Passwordでもkeychainでも、注入された環境変数をプロセスを通じてAIが参照できる可能性は残ります。
# AIがこれを実行したら、環境変数の中身が見えてしまう
echo $TEST_KEY
平文をディスクから排除しても、実行時にメモリ上に展開された認証情報はAIエージェントから見える状態です。これは個人の対策だけでは防ぎきれないため、チームとして仕組みで対処する必要があります。
最小権限の原則を徹底する
当然のことですが、改めて徹底します。環境ごとのキーはそれぞれの環境で管理し、開発環境に本番キーを置かないことが基本です。
具体的には、prd・stgの環境キーを分離し、AWS Secrets ManagerやSSM Parameter Storeに保存して、各環境から参照する構成にします。開発者のローカルPCに本番キーが存在しなければ、仮にAIが環境変数を読んでも本番環境への影響はありません。
AIに触れる部分はローテーションする
ゼロトラストの考え方で、AIがアクセスし得るキーは漏洩を前提に考えます。
開発環境のキーはAIコーディングツールから参照できる状態にある以上、漏洩のリスクをゼロにはできません。そのため、定期的にキーをローテーションする仕組みをあらかじめ作っておき、万が一漏洩しても被害を最小化できるようにしておきます。
感想
便利なものにはいつでもリスクが付き纏います。かといって、制限をガチガチにしてしまえばAIの便利さを失ってしまう。そのバランスが難しいところです。
今回、AIを便利に使うための環境作りに取り組む中で、セキュリティについて改めて見直すきっかけになりました。「AIに何を触らせて、何を触らせないか」を考えることは、そのまま認証情報の管理を見直すことにつながります。AIツールの導入が、結果としてセキュリティ意識を高めてくれたのは良い副産物だったと思います。