削除したはずの一文が、まだ公開されていた — バックアップを配信ディレクトリに置くな
「バックアップを取る」は安全側の行動ではない。置き場所を間違えると、消したはずの情報を公開する行為になる

昨日、自分のプライバシーポリシーから一文を削除しました。「アプリ内の設定から権利を行使できます」と書いてあるのに、その設定が実装されていなかったからです。書いてあるのに動かないのは、書いていないより悪い。だから消しました。
翌朝、配信ディレクトリを走査する自作の見張りを回したら、こう出ました。
検出5件 FAIL3 WARN0
[.bak] /apps/<アプリA>/privacy.html.bak-20260817 が200配信
[.bak] /apps/<アプリB>/privacy.html.bak-ccpa-2026-08-18 が200配信
[.bak] /apps/<アプリC>/privacy.html.bak-ccpa-2026-08-18 が200配信
取得してみると、中身は削除する前の版でした。つまり消したはずの一文は、隣のURLで誰でも読める状態のまま2日間公開されていた。消したのではなく、コピーを増やしていたわけです。
原因は「差し戻せるように」置いたバックアップだった
私の外科的なデプロイスクリプトは、上書きの前に必ずこうしていました。
# 差し戻せるように、上書き前の本番を日付つきで退避
cp ${dir}/privacy.html ${dir}/privacy.html.bak-${STAMP}
意図は完全に善意です。壊したときに1コマンドで戻せる。実際この習慣に何度も助けられました。問題は置き場所だけです。${dir} は静的ファイルの配信ディレクトリなので、そこに置いたファイルは拡張子が .html でなくても Web サーバーが素直に返します。実測でも3本とも HTTP 200 で本文が返ってきました(7,706 / 6,855 / 9,162 バイト)。
ここには2段階の被害があります。
- 1段目: 削除・修正したはずの記述が、別URLで生き続ける。法務系の文書だと「どちらが正か」が外から判定できません。
- 2段目: 検索エンジンがそれを拾うと、旧版のほうが検索結果に残ることがあります。
robots.txtはAllow: /なので防波堤になっていませんでした。
「バックアップを取るのは安全側の行動」という思い込みが、そのまま穴になりました。置き場所を1つ間違えると、バックアップは消したはずの情報を公開する行為に変わります。
なぜ「.html じゃないファイル」が返ってしまうのか
ここは誤解しやすいところです。privacy.html.bak-2026-08-18 は拡張子が .bak-2026-08-18 なので、一見すると「Webサーバーが知らない形式=返さない」ように思えます。実際は逆で、静的ファイルの配信は基本的に「そのパスにファイルがあれば返す」動作です。拡張子で決まるのは主に Content-Type の推定であって、配信するかどうかではありません。知らない拡張子なら既定の型が付くだけで、中身のバイト列はそのまま外に出ます。
つまり「変な名前にしておけば見られない」は成立しません。日付やハッシュを付けても、URLは推測できますし、そもそも推測されなくてもリンクや履歴から到達されます。守るなら、配信されない場所に置く・アクセス制御を掛ける・そもそも置かない、のどれかです。私は3つ目にしました。
2日間気づけなかったのは、見張りが週1だったから
もう一つ悪かったのは検知の間隔です。この見張りは週1回・月曜の朝に走る設定でした。問題のファイルが生まれたのは金曜18時台と土曜19時台。つまり最悪7日間、公開されたまま気づけない設計です。
ここで大事なのは「週1が一般的に悪い」ではありません。監視の間隔は、その事故が生まれる頻度に合わせるということです。この事故は自分がデプロイするたびに生まれます。デプロイは週1回ではありません。だから見張りも週1回ではいけなかった。走査は1回90秒ほど、外向きのHTTPリクエストは数十件。日次にしても実質的な負荷はありません。
直した3か所
1. 公開されている旧版を止める。削除ではなく、配信ディレクトリの外へ移動しました。中身が「戻せる状態」であることは残しつつ、外からは読めなくなります。移動後に本番のURLを実際に叩いて、旧版が404、本物が200のままでサイズも変わっていないことを確認しました。
旧版: 404 / 404 / 404
本物: 200 8,469B / 200 6,400B / 200 8,560B(移動前と同じ)
2. 再発源を断つ。バックアップを作っていたスクリプト2本を、配信ディレクトリの外に退避するよう書き換えました。片方は冒頭のコメントにも「.bak としてサーバ上に残す」と書いてあったので、そこも実装と合わせています。コメントだけ古いまま残すと、次に読む人(=半年後の自分)が同じ設計を再生産します。
3. 見張りを日次にする。週次トリガーを日次に付け替え、実際に1回起動して、ログに新しい行が増えることまで確認しました。トリガーを変えたときに実行内容(引数・タイムアウト)が消えていないことも見ています。
見張りの作り方で1つだけ譲らなかったこと
この見張りは、もともと「怪しいURLのリストを人が登録して、それを叩いて確認する」方式でした。今は違います。サーバ上の実ファイルを毎回列挙する方式です。
理由は単純で、リスト方式は新しく増えたものを永久に取りこぼすからです。実際、以前この方式だったとき、固定2URLしか見ておらず、別の2件が何週間も200で配信され続けていました。「登録したものが無事か」を測る検査は、「登録し忘れたもの」に対して常に緑を返します。緑が増えるほど安心してしまうぶん、リスト方式は害のほうが大きいと考えています。
同じ理由で、検査には必ず変異テスト(わざと壊して、ちゃんと落ちるか見る)を入れています。名前の判定なら「拾うべき名前」と「巻き込んではいけない名前」を両方通します。backup-guide.html や baklava.png を .bak と誤認する検査は、いずれ「誤検知が多いから」と無視されて死にます。
同じ穴を「全種類」洗ってから閉じる
3本を片付けたあと、そこで終わりにしませんでした。同じ理由で生まれた仲間が他にいないか、公開中の同種ページを全部機械で確認しています。今回でいえば、削除したはずの記述が他のアプリのページに残っていないかを全ページ取得して数え、残り0件であることを確認しました。
この確認で1つ学びがありました。最初に書いた確認スクリプトはフォルダの1階層しか見ておらず、その結果「2本のアプリで記述と実装が食い違っている」という結論が出ました。あわてて直しに行く前に、対象を1件だけ手で開いて突き合わせたところ、実装は下の階層のファイルに、ちゃんと存在していました。1階層しか見ない検査が作った偽の赤だったわけです。
検査を書いた直後の数字は、世界の事実ではなくその検査の性質を映しています。緑なら「壊しても落ちるか」を、赤なら「実物を1件だけ手で確認する」を、必ず1回挟むようにしています。今回はそのおかげで、直さなくていいものを直す(そして本当は直っていないと勘違いする)事故を回避できました。
持ち帰れる形にすると
- 配信ディレクトリに置いていいのは「配信したいもの」だけ。バックアップ・作業コピー・
.orig・.tmpは全部その外に置く。 - 本番を書き換えるスクリプトを書くときは、バックアップの出力先を最初に決める。「とりあえず隣に置く」がいちばん危ない。
- 監視の間隔は、事故が生まれる頻度に合わせる。デプロイのたびに生まれる事故を週1で見張るのは、設計として合っていない。
- 削除・訂正の作業は、「消えたか」ではなく「外から読めなくなったか」で確認する。ファイルを消したことと、公開が止まったことは別の事実です。
正直に書くと、この3本を見つけたのは偶然ではなく、別件で「昨日の作業のあと片付けが本当に終わっているか」を確認しに行ったからでした。作業の直後は、自分がいちばん「終わったつもり」になっています。終わったつもりの翌朝にもう一度だけ外から見る、というのを習慣にしておくと、この種のものはだいたいそこで捕まります。
よくある質問
本番の上書き前にバックアップを取るのは間違いなの?
バックアップ自体は正しい習慣です。間違いは置き場所だけです。静的配信のディレクトリにコピーを置くと、拡張子が .html でなくても Web サーバーはそのまま返してしまい、旧版が公開ページとして生き続けます。退避先は配信ディレクトリの外(サーバ内の非公開ディレクトリや手元)に決め、スクリプトを書く最初の段階で出力先を固定してください。
.bak が公開されていると具体的に何が困るの?
2つあります。1つは、修正・削除したはずの記述が別URLで読めてしまうこと。法務文書だと「どちらが正か」が外から判断できません。もう1つは検索エンジンに拾われることで、旧版のほうが検索結果に残る場合があります。robots.txt が Allow: / のままなら防げません。実害が出る前に、配信ディレクトリの実ファイルを列挙して確認するのが確実です。
置き忘れを見張る仕組みは、どう作るのが安全?
「怪しいURLを人が登録して叩く」方式ではなく、「サーバ上の実ファイルを毎回列挙する」方式にしてください。リスト方式は登録し忘れたものに対して常に緑を返すため、増えた分を永久に取りこぼします。加えて、わざと壊して検査が落ちることを確認する変異テストと、backup-guide.html のような無関係な名前を巻き込まないことの確認を、両方入れておくと長持ちします。