AIに作業させるとき、セキュリティで見るのは5箇所だった
AIと一緒にサイトを作っていて、公開の直前に点検した。
そうしたら、設定のままだと内部メモが全部ネットに出るところだった。収益化のTODO、未公開の記事の下書き、内部ツール。どれもリンクは張っていないが、URLを直接叩けば読める状態になる。
危ないのは、これがエラーにならないことだ。サイトは正常に表示されるし、ビルドも通るし、どこにも警告は出ない。気づかなければ、気づかないまま公開されていた。
静かに事故る。
その日に見た5箇所を、叩いたコマンドごと残しておく。
1. 公開ディレクトリに何が入っているか
静的サイトのホスティングは、指定したフォルダの中身を全部配信する。HTMLだけを選んで出す、という動きはしない。
つまりそのフォルダに .md のメモを置いていれば、それも配信される。
$ find projects/game-graphics -type f
projects/game-graphics/NEXT.md ← 収益化のTODO
projects/game-graphics/DEPLOY.md ← 内部の手順書
projects/game-graphics/articles/….md ← 未公開の記事下書き
projects/game-graphics/tools/gen-cards.js
projects/game-graphics/index.html
projects/game-graphics/about.html
上4つは出したくない。とくに1つ目には、何をいくらで売るつもりか、どのSNSにいつ投稿するつもりかまで書いてある。なので公開するものだけ site/ に分けて、ホスティング側の指定をそこに変えた。
site/ ← ここだけ配信する
index.html
about.html
econ.html
news.html
NEXT.md ← 配信されない
DEPLOY.md ← 配信されない
articles/ ← 配信されない
判断は簡単で、公開してよいものだけ site/ に入れる。迷ったら外に置く。外に置いて困るのは自分だけだが、中に置いて困るのは取り返しがつかない。
2. リポジトリが公開か非公開か
これは思い込みで間違える。私が間違えた。
私は自分のリポジトリを公開だと思っていて、スクリプトをGitHubのリンクで配ろうとした。確認したら非公開だった。
逆のパターンのほうが怖い。非公開のつもりで公開になっていると、中に入れた全部が読まれる。私のリポジトリには個人的な文章と仕事のルールが入っているので、公開になっていたら事故だった。
作った直後に1回確認して、あとは触らない。それだけでいい。
3. 鍵がコミットに入っていないか
AIにコードを書かせると、動かすためにAPIキーを直接書き込むことがある。動いてしまうので、そのまま通る。
$ grep -rIlE '(api[_-]?key|secret|token|BEGIN [A-Z ]*PRIVATE KEY|sk-[A-Za-z0-9]{20})' \
--exclude-dir=node_modules --exclude-dir=.git .
$ git ls-files | grep -i secret
引っかかった行は1つずつ中身を見る。変数名だけなら問題ない。値が入っていたら手遅れだ。その場合は、点検して安心する話ではなくなって、鍵を無効にして作り直すところから始めることになる。
私のところでは、鍵は環境変数と .secrets.env から読む形になっていて、そのファイルは無視の設定に入っていた。git ls-files でも1件も出なかった。
一度コミットしてしまうと、あとで消しても履歴に残る。消したから大丈夫、にはならない。
4. AIに渡してよい情報かどうか
これはツールの設定ではなく、こちらの運用の話だ。
原価、仕入先の名前、取引先、個人情報。この辺りは渡す前に一度止まったほうがいい。渡した情報がどこに残るかは、こちらからは見えないので。
私は自分のルールとして、書かないものを決めて文書にしてある。
記録しない: 原価・仕入価格 / 仕入先名・取引先名
公開しない: 店舗名・店舗URL・品番・ブランド名・仕入先システム名
決めておくと、判断が要らなくなるのが利点だ。毎回考えると、疲れているときに間違える。
書いたものが本当に守れているかも、機械で見たほうがいい。
$ for w in 原価 仕入先 取引先; do
echo -n "$w: "; grep -ril "$w" 公開するフォルダ/ | wc -l
done
全部0であることを、公開前に確認する。目視では抜ける。人間は、自分が書いたものを読むときに、書いたつもりの文章を読んでしまうので。
5. 勝手に外部と通信していないか
いちばん見つけにくいのがこれだ。目で追っても分からない。
AIは頼んでいないことを、気を利かせてやる。ファイル名を分かりやすく変えたり、値の表記を揃えたり、便利そうな部品を足したりする。整った形で出てくるので、見ただけでは気づけない。
セキュリティの文脈だと、外部サービスの読み込みが勝手に増えるのが怖い。フォントやアイコンを外部から読むコードは、書かせれば普通に出てくる。それ自体は一般的なやり方だが、読み込んだ先に閲覧者の情報が渡ることになる。
なので、作ったものが外と通信していないかを確認している。
$ grep -ohE '(src|href)="https?://[^"]+' *.html
(何も出なければ、外部リソースの読み込みは無い)
私が作っているツールは、全部これが空になるように作ってある。入力した内容もブラウザの中にしか保存しない。維持費がかからないのと、他人の情報を預からずに済むのが理由だ。
預かっていない情報は漏らせない。個人が作って長く置いておくものは、この形がいちばん強いと思っている。
見るのは、公開フォルダの中身、リポジトリの公開設定、鍵の混入、渡してよい情報の線引き、外部通信の有無。この5つだった。
全部やっても10分かからない。今日かかったのも、それくらいだ。
そして5つのうち3つは、AIが悪いのではなく設定と運用の問題だった。AIに作業させるから危ないというより、作るのが速くなったぶん、確認が追いついていないというのが実際のところだと思う。
作る速さは10倍になっても、確認する速さは変わらない。だからコマンドにして、毎回同じものを叩くようにしている。