対象:共用レンタルサーバー(Apache/.htaccess が使える環境)に Laravel など「public/ だけ公開する前提」のアプリを置いている人。実際の事故(→ .env全公開の話)から抽出した、自分の環境を守るための手順です。
当サイトの視点:これは個人のミスではない
レンタルサーバー黎明期の「public_html 直下に全部置く」文化に、public/ だけを晒す前提のLaravelが流入した結果、危険な配置が事実上の標準になってしまいました。各社の公式ドキュメントすら public_html 内にプロジェクトを置く例ばかりです。だから対策は個人の注意力ではなく仕組みにするのが正解です。具体的には、デプロイ手順のデフォルトを変えます。
正しい配置を図で押さえる
✗ 危険(本体を公開ルート直下)
public_html/ ├─ .env ← 読める! ├─ .git/ vendor/ └─ public/
✓ 安全(本体は外、public だけ)
app-laravel/ ← 公開ルート外 ├─ .env .git/ ← 到達不能 └─ public/ → public_html から require
自分の環境で、どの対策ができるか
同じ「.env を外に出さない」でも、サーバーの種類や権限によって取れる手段が違います。まず自分がどれに当たるかを確認してから、下の Step に進みます。
| 環境 | 恒久対策(本命) | 応急処置 | 注意点 |
|---|---|---|---|
| 共用レンタルサーバー(SSHあり) | 本体を公開フォルダの外へ移し、公開フォルダには小さな index.php だけ置く(Step 2) | .htaccess で拒否 | 公開フォルダ自体を symlink にすると 500 になる環境がある |
| 共用レンタルサーバー(FTPのみ) | FTPソフトで、本体を公開フォルダ(public_html など)の1つ上の階層へアップロードし直す | .htaccess で拒否 | 多くの共用サーバーでは公開フォルダの上にも書き込めるが、できない場合はサポートに確認する |
| 管理画面で公開フォルダを指定できる | 公開フォルダを app-laravel/public に直接向ける | 不要(ただし確認は必要) | 指定を変えたら、古い公開フォルダに本体のコピーが残っていないか消す |
| VPS(Apache) | VirtualHost の DocumentRoot を public/ に向ける | 設定ファイルに拒否ルール | AllowOverride None だと .htaccess は読まれない(Apache 2.4 の既定値) |
| VPS(Nginx) | root を public/ に向け、ドットで始まるファイルを拒否する | 設定ファイルに拒否ルール | Nginx は .htaccess を読まない |
どの環境でも、ゴールは同じです。公開フォルダの中に .env・.git・vendor/・storage/ が存在しない状態にします。Laravel の公式ドキュメントも、index.php をプロジェクトのルートへ移して公開すると多くの機密設定ファイルがインターネットに見えてしまう、と注意しています。
Step 1:応急処置(すぐできて元に戻せる)
公開ルートの .htaccess 冒頭に、機密ファイルを拒否するブロックを追記します(防御目的の設定例)。通常表示には影響しません。
# === SECURITY BLOCK ===
RedirectMatch 404 (?i)/\.(env|git)(\..*)?(/|$)
<FilesMatch "(?i)\.(sql|sql\.gz|bak|old|swp|save|orig|tgz)$|^credentials\.json$|\.bk[._]">
Require all denied
</FilesMatch>
<FilesMatch "(?i)^(phpinfo|info)\.php$">
Require all denied
</FilesMatch>
# /<app>/storage 等の内部ディレクトリが見えている場合
RedirectMatch 403 (?i)^/[^/]+/(storage|bootstrap/cache|config|database|resources|routes|tests|vendor)(/|$)
# === END ===応急処置はゴールではない
ブラックリストでは composer.lock や .gitignore など、拒否し忘れるファイルが必ず出ます。あくまで Step 2 までの時間稼ぎと考えます。
Step 2:構造改修(恒久対策)
アプリ本体を公開ルートの外へ移し、公開ルートには「読み込むだけの小さな入口」を置きます。
# 1. 本体を公開ルートの外へ(同一ファイルシステムなら mv は一瞬・atomic)
mv ~/example/public_html/app ~/example/app-laravel
# 2. 公開ルートに最小の入口だけ作る
mkdir -p ~/example/public_html/sub
cat > ~/example/public_html/sub/index.php <<'PHP'
<?php require __DIR__ . '/../../app-laravel/public/index.php';
PHP
# 3. Laravel public/.htaccess をコピー、静的アセットを symlink
# 4. 設定キャッシュをクリア
rm -f ~/example/app-laravel/bootstrap/cache/{config,services,packages,routes-v7}.php当サイトが運用で学んだ注意点:symlinkより bootstrap-redirect
「public_html 自体を public/ へのsymlinkにする」やり方は、登録済みサブドメインのdocrootだと追従せず500になる環境があります。docrootは実ディレクトリのまま、中の小さな index.php から絶対パスで require する「bootstrap-redirect型」のほうが、スコープ制約のある共用環境で安定します。さらに opcache が壊れたロードを記憶して500を返し続けることがあり、最終手段は入口ファイル名を変える(entry.php 等)です。
Step 3:鍵ローテーション(漏れていた前提で)
公開されていた期間があるなら、.env の鍵は見られた前提で入れ替えます。優先順は「外部API・OAuthシークレット → 暗号鍵 → メール → DB」。.env の項も参照。OAuthのシークレット再発行は refresh_token を無効化することがあるので、再認可フローを用意してから実施します。
Step 4:自己点検(習慣化)
最後に、自分のサイトで実際に漏れていないか確認します(自分の所有ドメインに対してのみ)。
# 200 で本文が返ったら公開されている。403/404 なら一旦OK
curl -sI https://あなたのドメイン/.env | head -1
curl -sI https://あなたのドメイン/.git/config | head -1これを公開のたびに確認する癖をつけると、配置ミスを早期に発見できます。
自分の環境で確認する方法(詳しく)
Step 4 の2行に加えて、次の点も確認しておくと見落としが減ります。どれも自分のサーバー・自分のドメインに対してだけ行ってください。
ステータスコードだけでなく中身を見る
アプリによっては、存在しないURLにもトップページを 200 で返すことがあります。その場合、ステータスだけでは判断できません。curl -s https://あなたのドメイン/.env | head -c 120 のように先頭だけ表示し、APP_KEY= や DB_PASSWORD= のような設定の行が出ないかを見ます。.git/HEAD なら ref: refs/heads/ で始まる行が出たら公開されています。
アプリの数だけ確認する
トップのドメインだけでなく、サブドメインやサブディレクトリに置いたアプリごとに同じ確認をします。配置ミスはアプリを増やすときにコピーされやすく、1つ直しても別の場所に残っていることがあります。
サーバー側で公開フォルダの中を探す
SSHが使えるなら、公開フォルダの中に危ないファイルが残っていないかを直接探します。find ~/public_html -maxdepth 4 \( -name ".env*" -o -name ".git" -o -name "*.sql" -o -name "*.zip" \) のように実行し、何も出なければ正常です。FTPしか使えない場合は、FTPソフトで隠しファイルを表示する設定にしてから一覧を見ます。
.htaccess が本当に効いているか確かめる
秘密を含まないダミーのファイル(例:中身が test だけの check.bak)を公開フォルダに置き、URLで開いて 403 になるか確認します。開けてしまったら .htaccess が読まれていないので、サーバーの種類(Nginx など)や設定を確認します。確認が終わったらダミーのファイルは消します。
デバッグモードが切れているか確認する
.env の APP_ENV が production、APP_DEBUG が false になっているかを見ます。Laravel の公式ドキュメントは、本番で APP_DEBUG を true にすると機密の設定値が利用者に見えるおそれがある、としています。SSHがあれば php artisan about --only=environment でも確認できます。
よくある間違いと直し方
- .env だけ消して .git を残す:
.gitが公開されていると、過去のコミットに入っていた.envや鍵まで復元されるおそれがあります。.gitも公開フォルダの外へ出し、一度でもコミットしていた秘密は再発行します。 .env.bakや.env.oldなどのコピーを公開フォルダに置いたままにする:本物の値が入ったコピーは.envと同じ扱いです。公開フォルダの外へ移すか削除します。.env.exampleにはダミーの値だけを書きます。- プロジェクトを丸ごと固めた ZIP をアップロードし、展開後も残している:ZIP の中に
.envが入っています。展開したらすぐ消します。 - 本番で
APP_DEBUG=trueのまま運用する:エラー画面から設定値が見えるおそれがあります。本番では必ずfalseにします。 .htaccessを書いたので安全だと思い込む:Nginx やAllowOverride Noneの環境では読まれません。上のダミーファイルの方法で、効いているかを確かめます。APP_KEYをいきなり差し替える:Laravel の公式ドキュメントによると、鍵を変えるとログイン中の利用者は全員ログアウトになり、古い鍵で暗号化したデータは復号できなくなります。Laravel 11 以降なら、古い鍵をAPP_PREVIOUS_KEYSに入れてから差し替えます。
実例:公開された .env が大量に集められた事例
2024年8月、あるセキュリティ企業の調査部門は、Webサーバー上で公開されていた .env を自動で集め、中に書かれたクラウドの認証情報を使ってデータを持ち出し、身代金を要求する活動を報告しました。報告によると、対象になったドメインは約11万、集められた環境変数は9万件を超え、そのうち約7,000件がクラウドサービス、約1,500件がSNSアカウントの認証情報でした。
報告は、原因をクラウド側の脆弱性ではなく、被害組織が誤って .env を公開していた設定ミスだとしています。ここから分かることは2つです。
- 公開された
.envは、人が偶然見つけるのではなく、プログラムで大量に探されている - 1つの
.envから、クラウドやメールなど別のサービスへ被害が広がる
小さなサイトだから見つからない、とは考えないでください。同じ配置ミスを匿名化した事例は Laravelの .env が外部から見られる状態だった事例 にまとめています。
次に読む
- 事故:.env が全公開されていた話(全記録)
- 用語:.env とは
- 入門:.env と APIキーは何が危ないのか
- 事業者側の事故:レンタルサーバーが不正アクセスされたとき、利用者は何をすべきか(自分の設定では防げない類型の備え)
- 侵入の確認:サイト・サーバーが不正アクセスされたか調べる方法(.env が公開されていたと分かったときの痕跡の探し方)
出典
- Laravel 公式ドキュメント「Deployment」(
public/index.phpに向ける・プロジェクトのルートから公開しない・本番ではAPP_DEBUG=false): laravel.com - Laravel 公式ドキュメント「Configuration」(
.envをソース管理に入れない、Debug Mode): laravel.com - Laravel 公式ドキュメント「Encryption」(
APP_KEYの差し替えとAPP_PREVIOUS_KEYS): laravel.com - Apache HTTP Server 2.4「core - AllowOverride」(
Noneのとき.htaccessは読まれない、既定値はNone): httpd.apache.org - Apache HTTP Server 2.4「.htaccess files」(使うべき場面と注意): httpd.apache.org
- OWASP「WSTG-CONF-04 Review Old Backup and Unreferenced Files for Sensitive Information」: owasp.org
- Unit 42(Palo Alto Networks)「Leaked Environment Variables Allow Large-Scale Extortion Operation in Cloud Environments」(2024年8月15日): unit42.paloaltonetworks.com