2026年9月30日

2026年9月30日

WordPressのWebサーバーのセキュリティ設定(Apache)

はじめに

Apacheのデフォルト設定はWordPress向けに最適化されておらず、サーバーバージョン情報の公開・ディレクトリ一覧表示・不要なモジュールが有効になっているなど、攻撃者にとって有利な情報を提供してしまいます。適切なセキュリティ設定でリスクを大幅に低減できます。

症状・原因

  • Apacheのバージョン情報がエラーページやレスポンスヘッダーに表示されている
  • ディレクトリにindex.phpがない場合にファイル一覧が表示される
  • .htaccessファイルに設定を追加してもWordPressに反映されない
  • 不正なHTTPメソッド(TRACE・DELETE等)が許可されている

解決手順

ステップ1:現在のApache設定を診断する

# Apache のバージョン確認
apache2 -v

# 現在の設定を確認
apache2ctl -M | grep -E "rewrite|headers|ssl"

# サーバー情報がレスポンスヘッダーに含まれているか確認
curl -sI https://example.com/ | grep -i "server\|x-powered"

# エラーレスポンスにサーバー情報が含まれているか確認
curl -s https://example.com/nonexistent | grep -i "apache"

# 有効なモジュールを確認
apache2ctl -M 2>/dev/null | sort

ステップ2:Apache のセキュリティ設定を強化する

# /etc/apache2/conf-available/security.conf を編集
sudo nano /etc/apache2/conf-available/security.conf
# /etc/apache2/conf-available/security.conf

# サーバーバージョン情報を非表示
ServerTokens Prod
ServerSignature Off

# ディレクトリリストを無効化
Options -Indexes

# シンボリックリンクを禁止
Options -FollowSymLinks

# .htaccess ファイルの上書きを許可(WordPress に必要)
AllowOverride All

# 不要な HTTP メソッドを無効化
<LimitExcept GET POST HEAD>
    Order Deny,Allow
    Deny from all
</LimitExcept>

# ヘッダーインジェクション対策
Header always unset X-Powered-By
Header always unset Server

# ETag を無効化(inode 情報の漏洩防止)
FileETag None
Header unset ETag
# 設定を有効化
sudo a2enconf security

# 必要なモジュールを有効化
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2enmod ssl

# 設定を検証
sudo apache2ctl configtest

# Apache を再起動
sudo systemctl reload apache2

ステップ3:WordPress 用 VirtualHost を設定する

# /etc/apache2/sites-available/wordpress.conf

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # HTTP → HTTPS リダイレクト
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/html

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # TLS 1.2 以上のみ許可
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256

    <Directory /var/www/html>
        Options -Indexes -FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # wp-config.php へのアクセスを禁止
    <Files wp-config.php>
        Require all denied
    </Files>

    # xmlrpc.php をブロック
    <Files xmlrpc.php>
        Require all denied
    </Files>

    # .htaccess・.htpasswd を保護
    <FilesMatch "^\.ht">
        Require all denied
    </FilesMatch>

    # バックアップファイルを保護
    <FilesMatch "\.(sql|bak|log|sh)$">
        Require all denied
    </FilesMatch>
</VirtualHost>

ステップ4:.htaccess でセキュリティを強化する

# /var/www/html/.htaccess: WordPress セキュリティ設定

# WordPress リライトルール
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

# セキュリティヘッダーを追加
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

# PHP の実行を uploads ディレクトリで禁止
<IfModule mod_rewrite.c>
    RewriteRule ^wp-content/uploads/.*\.(php|phtml|php5|phar)$ - [F,L]
</IfModule>

# スクリプトインジェクション対策
<IfModule mod_rewrite.c>
    RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
    RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
    RewriteRule ^ index.php [F,L]
</IfModule>

ステップ5:mod_security を有効化する

# mod_security をインストール
sudo apt install libapache2-mod-security2 -y

# OWASP CRS をインストール
sudo apt install modsecurity-crs -y

# モジュールを有効化
sudo a2enmod security2

# 設定ファイルをコピー
sudo cp /etc/modsecurity/modsecurity.conf-recommended \
    /etc/modsecurity/modsecurity.conf

# 検出モードを有効化(まず DetectionOnly で様子を見る)
sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' \
    /etc/modsecurity/modsecurity.conf

# WordPress に必要なルールの例外を設定
sudo nano /etc/modsecurity/wordpress-exclusions.conf
# /etc/modsecurity/wordpress-exclusions.conf
# WordPress 管理画面の誤検知を除外

<LocationMatch "^/wp-admin/">
    SecRuleRemoveById 981173
    SecRuleRemoveById 960017
</LocationMatch>

# REST API の誤検知を除外
<LocationMatch "^/wp-json/">
    SecRuleRemoveById 200003
</LocationMatch>

注意事項

  • AllowOverride Allを設定すると.htaccessが有効になりますが、パフォーマンスに影響します。必要なディレクトリのみに限定することを検討してください
  • mod_securityをSecRuleEngine On(ブロックモード)にする前に、必ずDetectionOnlyで誤検知を確認してください。WordPressの管理画面が誤ってブロックされる場合があります
  • SSL/TLS設定後はssl-labs.comなどでA+評価になっているか確認してください

まとめ

Apacheのセキュリティ設定は①ServerTokens Prod・ServerSignature Offでバージョン情報を非表示、②Options -Indexes -FollowSymLinksでディレクトリリストとシンボリックリンクを禁止、③VirtualHostでSSLProtocol all -TLSv1 -TLSv1.1・wp-config.php・xmlrpc.phpへのアクセスを拒否、④.htaccessにセキュリティヘッダー・uploads内PHP実行禁止・SQLインジェクション対策RewriteRuleを追加、⑤mod_securityをDetectionOnlyで試験後にOnに切り替えてWordPress管理画面の誤検知ルールを除外します。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲