公開前5分チェック③ ログアウトして画像URLを直接開く

ログアウトした状態でアップロード画像やPDFのURLを直接開いて、表示されたらそのファイルは全員に公開されています。ページの鍵とファイルの鍵は別。AIは動作確認のため公開バケットを選ぶ。非公開バケット+本人だけ+期限付きURLに直す頼み方と確かめ方。

動画で見る

結論から

AIで作ったアプリを公開する前に、自分の手でできる5分チェックの3つ目。ログアウトした状態(シークレットウィンドウ)で、アップロードした画像・PDFのURLを直接開いてみてください。表示されたら、そのファイルは全員に公開されています。

この記事で伝えたいのは、この一点だけです。

  • 「予約ページはログインしないと見えない」と「予約ページに貼った免許証の画像が見えない」は、別の扉。ページを守っても、ファイルは守られていない
  • 画像・PDF・CSVは、ページとは別の場所(ストレージ)に置かれ、別のURLで配られる。AIは動作確認のため、その場所を「公開」で作ることが多い
  • 直すのは、ストレージを「非公開」にして、本人だけに期限付きのURLを渡すこと。AIへの頼み方と確かめ方を下に書いた

動画版(約2分半)は本文の上に埋め込んであります。

① 何が起きるのか:ログアウトしても、免許証が開けた

前回までと同じ、AIで作った美容室の予約アプリ(デモ用に用意した架空のもの)で試します。予約時に本人確認書類をアップロードする機能があります。

  1. 佐藤さんとしてログインし、自分の予約ページで免許証の画像を右クリック →「画像アドレスをコピー」。URLは .../uploads/license.jpg
  2. シークレットウィンドウ(未ログイン)を開き、そのURLを貼って Enter
  3. 表示されたのは 運転免許証の画像。氏名・生年月日・住所・番号まで、そのまま読めた。右上は「未ログイン」のまま

予約ページのほうは、ログインしないと開けません。でも、そのページに貼ってある画像は、URLさえ分かれば誰でも開ける。ページの鍵と、ファイルの鍵は別なのです。

ページの鍵と、ファイルの鍵は別

② なぜ起きるのか:画像は「ページ」ではなく「ファイル」

理由1:ファイルは、別の場所から配られている。

アプリの画面(HTML)はサーバーが作りますが、画像やPDFは「ストレージ」と呼ばれる別の置き場(Supabase Storage、Firebase Storage、S3、Cloudflare R2 など)に置かれ、そこから直接ブラウザへ配られます。画面のログイン確認は、この置き場を通りません。

理由2:AIは、置き場を「公開」で作る。

Supabase の Storage には「公開バケット」と「非公開バケット」があります。公開バケットは、公式ドキュメントのとおり「URLを知っていれば誰でも読める」設定です。AIは「画像を表示して」と頼まれると、いちばん簡単に表示できる公開バケットを選びます。<img src="https://…/storage/v1/object/public/uploads/license.jpg"> と書けば、認証なしで画像が出るからです。動作確認は一発で通ります。

理由3:ファイル名が推測できる。

セキュリティ会社の Supabase 監査では、uploads/license.jpg invoices/2025.pdf のように「誰のファイルか」がパスに無い構造が多く、ファイル名を1つ推測しただけで他人の書類に届いた例が報告されています。前回の「URLの数字を変える」と同じことが、ファイルでも起きます。

③ どう直すのか:非公開にして、本人にだけ期限付きURLを渡す

直すのは3点セットです。以下をそのまま AI ツールに貼ってください。

「アップロードされたファイル(画像・PDF・CSV)の置き場を確認して、本人確認書類・請求書・顔写真など個人に紐づくものは、公開バケットから非公開バケットに移してください。ファイルのパスは {user_id}/… のように所有者IDで始める形にして、ストレージのポリシーで本人だけが読めるようにしてください。画面に表示するときは、サーバー側で本人確認をしてから期限付きの署名付きURL(60秒〜数分)を発行して渡す形に書き換えてください。対象になったファイルとバケットの一覧も出してください。」

  • 非公開バケット:URLを知っているだけでは開けない
  • 所有者IDで始まるパス:ポリシーが「誰のものか」を判定できる
  • 署名付きURL:本人が表示するときだけ、短時間有効なURLを発行する

「公開してよい画像」(商品写真、ロゴ)は公開バケットのままで構いません。個人に紐づくものだけを移します。

④ 直ったかを確かめる:同じ手順で、もう一度

  • シークレットウィンドウで同じURLを開く → 「ログインが必要です」「403」「Object not found」なら合格
  • 署名付きURLを、数分後にもう一度開く → 期限切れで開けなければ合格。ずっと開けるなら、期限が長すぎる
  • 別のアカウントでログインして開く → 403 なら合格(他人の書類が見えない)
  • ファイル名を変えて開く → license.jpg → license2.jpg、1.jpg などで他人のファイルが出ないか

確認する対象は、画像だけではありません。PDF(請求書・契約書)、CSV(エクスポート)、音声、動画、すべて同じ扉です。

自分で直せないとき:エンジニアに送る一文

「アップロードした本人確認書類のURLが、ログアウト状態でも開けます(例:/uploads/license.jpg)。個人に紐づくファイルを非公開バケットに移し、本人だけが読めるポリシーと、期限付きの署名付きURLでの表示に変えてください。他のアップロード先も同じ確認をお願いします。」

よくある質問

URLが長くてランダムなら、推測されないから大丈夫では。

推測は難しくなりますが、URLは共有・履歴・スクリーンショット・メール転送で漏れます。漏れた瞬間に誰でも開けるのは同じです。ランダムなURLは「おまけ」で、非公開バケット+署名付きURLが本体です。

Firebase Storage を使っています。

同じ考え方です。Storage のセキュリティルールで allow read: if request.auth.uid == userId のように本人だけに絞ります。AIに「Storage のルールを、パスの所有者だけが読める形にして」と頼んでください。ルールが allow read: if true になっていたら、公開と同じです。

商品画像も非公開にすべきですか。

不要です。誰に見えてもよいものは公開のままで速く配れます。分けるのは「個人に紐づくかどうか」だけです。

このチェックが通れば、公開して大丈夫ですか。

これは「公開前5分チェック」の3つ目です。①URLの数字、②/admin、③画像URL、この3つと「フロントのキー」「RLS」で、自分で見つけられる事故の大半は潰せます。それでも不安が残る部分だけを、エンジニアに見てもらうのが、いちばん費用対効果の高い順番です。