2026年5月20日

2026年5月20日

WordPressでディレクトリリスティングを無効化する方法

はじめに

ディレクトリリスティング(ディレクトリ一覧表示)が有効になっていると、index.phpのないディレクトリにアクセスした際にファイル一覧が表示されます。プラグインファイルやテーマファイルの構成が丸見えになり、攻撃者に脆弱なバージョンを特定される危険があります。

症状・原因

  • https://example.com/wp-content/uploads/2024/ にアクセスするとファイル一覧が表示される
  • セキュリティスキャンで「ディレクトリリスティングが有効です」と指摘された
  • wp-content/plugins/wp-content/themes/ のファイル構造が外部から確認できる
  • Apacheのデフォルト設定(Options Indexes)が有効になっている

解決手順

ステップ1:現在の状態を確認する

# ディレクトリリスティングが有効か確認
curl -I https://example.com/wp-content/uploads/
# "200 OK" + HTMLにファイル一覧 → リスティングが有効(危険)

# curl でレスポンスボディを確認
curl -s https://example.com/wp-content/uploads/ | grep -i "index of\|parent directory"
# "Index of" が含まれる → リスティングが有効

# wp-content/plugins/ も確認
curl -s https://example.com/wp-content/plugins/ | grep -i "index of"

# Apache の設定を確認(サーバーにアクセスできる場合)
apache2ctl -M | grep autoindex
# autoindex_module が有効かどうか

ステップ2:Apacheで無効化する(.htaccess)

# WordPress ルートの .htaccess に追加
# ディレクトリリスティングをサイト全体で無効化
Options -Indexes

# もしくは個別ディレクトリに .htaccess を設置
# /var/www/html/wp-content/uploads/.htaccess
Options -Indexes
# WordPress ルートの .htaccess に追記
echo "Options -Indexes" >> /var/www/html/.htaccess

# wp-content 配下の主要ディレクトリにも適用
for dir in uploads plugins themes; do
    echo "Options -Indexes" >> /var/www/html/wp-content/${dir}/.htaccess
done

# 設定後に確認
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/
# 403 Forbidden が返れば成功

ステップ3:Nginxで無効化する

# Nginx の設定ファイル(/etc/nginx/sites-available/example.com)
server {
    # ... 既存の設定 ...

    # ディレクトリリスティングを無効化(デフォルトは off)
    autoindex off;

    # wp-content/uploads での PHP 実行も同時に禁止
    location ~* /wp-content/uploads/.*\.php$ {
        deny all;
        access_log off;
    }
}
# Nginx 設定をテストして反映
sudo nginx -t && sudo systemctl reload nginx

# 確認
curl -o /dev/null -s -w "%{http_code}" https://example.com/wp-content/uploads/
# 403 が返れば成功

ステップ4:index.phpを設置してフォールバックする

# index.php が存在しないディレクトリに空のindex.phpを設置
# .htaccess が使えない環境での代替手段

# WordPress は自動的に主要ディレクトリに index.php を設置するが
# uploads サブディレクトリは設置されない場合がある

find /var/www/html/wp-content -type d | while read dir; do
    if [ ! -f "${dir}/index.php" ]; then
        echo "<?php // Silence is golden." > "${dir}/index.php"
        echo "Created: ${dir}/index.php"
    fi
done
// functions.php: メディアアップロード時に index.php を自動生成
add_action('wp_handle_upload', function(array $upload): array {
    $upload_dir = dirname($upload['file']);
    $index_file = $upload_dir . '/index.php';

    if (!file_exists($index_file)) {
        file_put_contents($index_file, "<?php\n// Silence is golden.\n");
    }
    return $upload;
});

ステップ5:定期的な監視スクリプトを設定する

# ディレクトリリスティングの状態を定期確認するスクリプト
cat > /usr/local/bin/check-dir-listing.sh << 'EOF'
#!/bin/bash
SITE_URL="https://example.com"
ADMIN_EMAIL="admin@example.com"
DIRS=("wp-content/uploads/" "wp-content/plugins/" "wp-content/themes/")

for dir in "${DIRS[@]}"; do
    response=$(curl -s "${SITE_URL}/${dir}" | grep -i "index of")
    if [ -n "$response" ]; then
        echo "[警告] ディレクトリリスティングが有効: ${SITE_URL}/${dir}" | \
            mail -s "[セキュリティ警告] ディレクトリリスティング検出" "$ADMIN_EMAIL"
    fi
done
EOF
chmod +x /usr/local/bin/check-dir-listing.sh

# 毎日確認
echo "0 3 * * * root /usr/local/bin/check-dir-listing.sh" > /etc/cron.d/wp-dir-listing-check

注意事項

  • Options -Indexes.htaccessが有効(AllowOverride AllまたはAllowOverride Options)な場合のみ機能します。サーバー設定でAllowOverride Noneになっている場合はhttpd.confまたはapache2.confで設定が必要です
  • WordPress標準の.htaccess# BEGIN WordPress# END WordPress)の外側に追記してください。WordPressが.htaccessを書き換えるとブロック内の設定が上書きされます
  • Nginxはautoindexがデフォルトでoffのため通常は無効化済みです。ただしautoindex on;が設定されている場合は明示的にoffに変更してください

まとめ

ディレクトリリスティングの無効化は①curl -s example.com/wp-content/uploads/ | grep "Index of"で状態確認、②Apacheは.htaccessOptions -Indexesを追記、③Nginxはautoindex offを確認・設定、④index.php)を各ディレクトリに設置してフォールバック、⑤curl -w "%{http_code}"で403が返ることを確認します。

お気軽にご相談ください