公開した覚えのないファイルが、URLを直接叩くだけで誰でも見られる状態になっていることがあります。原因の代表が ディレクトリリスティング(ディレクトリ一覧表示) と バックアップ・一時ファイルの置き忘れ です。
- 対象: nginx / Apache でサイトを運用している Web 担当者・制作会社の方
-
解決すること: フォルダの中身が一覧表示されたり、
config.php.bakのような編集途中ファイルがダウンロードされたりするのを、コピペできる設定で塞ぐ -
前提知識: 設定ファイルを編集して
reloadできること。それ以外の専門知識は不要です
この記事は「設定を強める方向」だけを扱います。攻撃の再現手順は載せません。
.git/.envの露出対策は別記事にまとめてあるので、本記事はディレクトリ一覧とバックアップファイルに絞ります(リンクは末尾の関連記事に)。
なぜ「丸見え」が起きるのか
Web サーバは「リクエストされた URL に対応するファイルをそのまま返す」のが基本動作です。問題は次の2つの挙動です。
-
ディレクトリリスティング:
index.htmlなどのインデックスファイルが無いフォルダにアクセスされると、サーバがそのフォルダ内の全ファイル一覧を自動生成して返してしまう。/uploads/や/backup/の中身がそっくり見えてしまうことがあります。 -
バックアップ・一時ファイルの直接ダウンロード:
wp-config.phpを編集するときに作ったwp-config.php.bakや、エディタが残すindex.php~、settings.php.swpなどは、URL を直接指定すればPHP として実行されずソースのまま返されます。中に DB パスワードや API キーが書かれていれば、それが平文で漏れます。
どちらも「リンクを張っていないから大丈夫」は通用しません。フォルダ名やファイル名は推測・総当たりで到達されます。置かない・見せないの両方で守るのが基本です。
対策1: ディレクトリリスティングを止める
nginx
nginx はデフォルトで autoindex off(一覧表示しない)ですが、過去の設定や配布テンプレートで on になっていることがあります。明示的に off を宣言しておくと安全です。
server {
# サーバ全体でディレクトリ一覧表示を無効化
autoindex off;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
autoindex on を書いている location ブロックが無いか、設定全体を確認してください。
# autoindex on が残っていないか洗い出す
sudo grep -rn "autoindex" /etc/nginx/
Apache
Apache は Options Indexes が有効だと一覧表示します。-Indexes で無効化します。サーバ設定(apache2.conf / httpd.conf)の該当 <Directory> ブロック、または公開ディレクトリ直下の .htaccess に書きます。
# /var/www/html などドキュメントルートの <Directory> に
<Directory "/var/www/html">
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
.htaccess で手早く塞ぐなら次の1行だけでも効きます。
# .htaccess の先頭に置くだけ
Options -Indexes
設定を変えたら反映します(構文チェックを必ず先に)。
# nginx
sudo nginx -t && sudo systemctl reload nginx
# Apache
sudo apachectl configtest && sudo systemctl reload apache2
対策2: バックアップ・一時ファイルへのアクセスを遮断する
一覧表示を止めても、ファイル名を直接指定されれば中身は返ってしまいます。そこで拡張子・ファイル名パターンでアクセス自体を拒否します。対象にするのは、現場でよく残るこのあたりです。
| パターン | 残す原因の例 |
|---|---|
.bak .old .orig .save
|
手動編集前のコピー |
.swp .swo
|
vim の編集中スワップ |
末尾 ~
|
Emacs などの自動バックアップ |
.sql .dump
|
DB のエクスポート置き忘れ |
.log .inc
|
ログ・インクルード片 |
nginx
# バックアップ・一時ファイルへのアクセスを 404 で遮断
location ~* \.(bak|old|orig|save|swp|swo|tmp|sql|dump|log|inc)$ {
deny all;
return 404;
}
# 末尾チルダ(エディタの自動バックアップ)を遮断
location ~ ~$ {
deny all;
return 404;
}
return 404 にしているのは、403(拒否)だと「そこにファイルが存在する」ことが分かってしまうためで、存在を隠す 404 のほうが安全です。
Apache
.htaccess または <Directory> 内に FilesMatch で記述します。
# バックアップ・一時ファイルを拒否
<FilesMatch "\.(bak|old|orig|save|swp|swo|tmp|sql|dump|log|inc)$">
Require all denied
</FilesMatch>
# 末尾チルダの自動バックアップを拒否
<FilesMatch "~$">
Require all denied
</FilesMatch>
Apache 2.2 系では
Require all deniedではなくOrder allow,deny/Deny from allを使います。2.4 以降は上記でOKです。
対策3: そもそも公開領域に置かない
設定で塞ぐのは「保険」です。根本対策は公開ディレクトリ(ドキュメントルート)にバックアップを作らないこと。運用ルールとして次を徹底します。
- 編集前バックアップは
/var/backups/などドキュメントルートの外に置く - DB ダンプ(
.sql)を一時的にも公開フォルダに出力しない - リリース時に作業ファイルが混入していないか確認する
# 公開ディレクトリに残ったバックアップ・一時ファイルを棚卸し
find /var/www/html -regextype posix-extended \
-regex '.*\.(bak|old|orig|save|swp|swo|sql|dump|inc)$' -o -name '*~'
ヒットしたファイルは、中身を確認のうえ公開領域の外へ退避するか削除します。
確認方法(設定後のセルフチェック)
設定を入れたら、外から見て塞がっているかを curl で確認します。-I はヘッダのみ取得するオプションです。
# 1) ディレクトリ一覧が出ないか(200 で一覧本文が返ったら NG / 403・404 が正常)
curl -sI https://example.com/uploads/
# 2) バックアップファイルが取得できないか(404 が正常)
curl -sI https://example.com/wp-config.php.bak
curl -sI https://example.com/index.php~
# 3) 念のため本文も確認(空 or Not Found なら OK)
curl -s https://example.com/wp-config.php.bak | head
HTTP/1.1 404 Not Found や 403 Forbidden が返れば塞がっています。200 OK で中身が返ってきたら設定が効いていないので、対象の location / <Directory> の適用範囲を見直してください。
WordPress を使っている場合の注意
WordPress では更新・移行プラグインが /wp-content/ 配下に .sql や .zip のバックアップを残すことがあります。プラグインのバックアップ保存先を公開領域の外に設定し、上の find で定期的に棚卸ししてください。wp-config.php.bak は特に危険(DB 認証情報が平文)なので最優先で確認します。
まとめ
- ディレクトリ一覧表示は nginx は
autoindex off、Apache はOptions -Indexesで止める -
.bak.old~.swp.sqlなどは拡張子・パターンでアクセス自体を 404 で遮断する - 設定は保険。根本は公開領域にバックアップを作らない運用と、
findでの定期棚卸し - 入れたら
curl -Iで「404 が返るか」を必ず確認する
リンクを張っていなくても、ファイル名は推測されます。一覧と置き忘れの両方を塞いで、「公開したつもりのないファイル」をゼロにしておきましょう。
関連記事
- 「.git」「.env」が世界に公開されていませんか? ── 情報漏えい事故を1行で防ぐ設定
- Webサイトに最低限入れるべきHTTPセキュリティヘッダ7種と設定例
- WordPressセキュリティ 最低限やることチェックリスト10
本記事のような露出設定は、Webサイトを9つの守りでまるごと守る「サイトドック」の月次の定期健診でまとめて確認できます → https://sitedock.jp