WordPressサイトが突然、知らないショッピングサイトにリダイレクトされる——。

これは「SEOスパム攻撃」と呼ばれる典型的なハッキング手口のひとつです。Googleからのアクセスだけ別サイトに誘導し、サイト管理者が直接URLを入力すると正常に見えるため、被害に気づくのが遅れやすい攻撃です。

セキュリティ対策にはさまざまな方法がありますが、まず最初に手をつけるべきなのがサーバーの設定ファイル .htaccess です。プラグインのインストール不要で、コードを貼り付けるだけで効果が出ます。

この記事では、コピペで使える .htaccess のセキュリティ設定を7つ紹介します。

    .htaccess とは?

    .htaccess(ハットアクセス)は、Apacheサーバーに置くことでディレクトリ単位でサーバーの挙動を制御できる設定ファイルです。WordPressをインストールすると、ルートディレクトリに自動生成されます。

    この1ファイルで、アクセス制限・リダイレクト・セキュリティヘッダーの設定など、多くのことができます。逆に言えば、ここを改ざんされると攻撃者に思い通りの制御を与えてしまうため、保護が重要です。

    対策1:重要ファイルへのアクセス制限

    wp-config.php はデータベースのパスワードなど、サイト運営に必要な機密情報が含まれた最重要ファイルです。外部から直接アクセスできないよう制限します。

    # WordPress重要ファイルへのアクセス制限
    <FilesMatch "^(wp-config\.php|.*\.(hta)|wp-mail\.php|install\.php|xmlrpc\.php)___PRE_BLOCK_0___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    
    # WordPressのバージョン情報漏洩防止
    <FilesMatch "^(readme\.html|license\.txt)___PRE_BLOCK_0___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    

    readme.htmllicense.txt はWordPressのバージョンが記載されているため、攻撃者に脆弱性の特定を許す情報源になります。あわせて非公開にしておきましょう。

    対策2:ディレクトリリスティングの防止

    Options -Indexes の1行を追加するだけで、ファイルが一覧表示されるのを防げます。

    # ディレクトリリスティング防止
    Options -Indexes
    

    この設定がない状態で https://example.com/wp-content/uploads/ にアクセスすると、アップロードされたファイルが一覧表示されてしまうことがあります。個人情報を含むファイルがある場合は特に重要な設定です。

    対策3:wp-includesディレクトリ内のPHPファイルを直接実行禁止

    wp-includes はWordPressのコアファイルが格納されたディレクトリです。ここにあるPHPファイルはWordPressが内部的に呼び出すもので、外部から直接URLでアクセスされる必要はありません。

    # wp-includes内のPHPを直接実行禁止
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteBase /
      RewriteRule ^wp-admin/includes/ - [F,L]
      RewriteRule !^wp-includes/ - [S=3]
      RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
      RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
      RewriteRule ^wp-includes/theme-compat/ - [F,L]
    </IfModule>
    

    今回対応した実際の感染事例では、wp-includes ディレクトリに偽装されたバックドアが仕込まれていました。バックドアはCSS・画像ファイルに見せかけて配置されており、削除しても自動復元される「永続化」の仕組みまで備えていました。

    対策4:バックアップ・ログファイルの保護

    .bak.sql.zip などの拡張子のファイルが公開ディレクトリに残っていると、データベースの中身やファイル一式をそのまま取得されるリスクがあります。

    # バックアップファイルやログファイルの保護
    <FilesMatch "\.(bak|log|sql|tar|gz|zip)___PRE_BLOCK_3___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    

    対策5:セキュリティヘッダーの設定

    ブラウザに対して「このサイトの制約」を伝えるセキュリティヘッダーを設定します。XSS(クロスサイトスクリプティング)やクリックジャッキングなどの攻撃を防ぐ効果があります。

    # セキュリティヘッダー設定
    <IfModule mod_headers.c>
      # XSS Protection
      Header set X-XSS-Protection "1; mode=block"
      # MIME Type スニッフィング防止(ファイル偽装対策)
      Header set X-Content-Type-Options "nosniff"
      # クリックジャッキング防止
      Header set X-Frame-Options "SAMEORIGIN"
      # HTTPS強制(HSTS)
      Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
      # Referrer Policy
      Header set Referrer-Policy "strict-origin-when-cross-origin"
      # Feature Policy
      Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
    </IfModule>
    

    各ヘッダーの役割:

    ヘッダー 役割
    X-XSS-Protection ブラウザ側のXSSフィルターを有効化
    X-Content-Type-Options ファイルの種類を偽装した攻撃を防ぐ
    X-Frame-Options 他サイトのiframeに埋め込まれることを防ぐ
    Strict-Transport-Security HTTPSへのアクセスを強制する
    Referrer-Policy 参照元情報の送信範囲を制限する

    対策6:REST APIへのアクセス制限

    WordPress REST APIは便利な機能ですが、未認証のままでは投稿データやユーザー情報が外部から取得できる状態になっています。ログイン済みユーザー以外のアクセスを制限します。

    # REST APIへのアクセス制限(認証済みユーザーのみ許可)
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteCond %{REQUEST_URI} ^/wp-json/(.*)$ [NC]
      RewriteCond %{HTTP_COOKIE} !wordpress_logged_in [NC]
      RewriteRule ^(.*)$ - [R=403,L]
    </IfModule>
    

    注意: REST APIを使うプラグイン(フォームプラグイン、モバイルアプリ連携など)を使用している場合は、動作確認を行ってください。

    対策7:HTTPS強制リダイレクト

    HTTPでアクセスされた場合、自動的にHTTPSにリダイレクトします。SSL証明書を導入している場合は必須の設定です。

    # HTTPS強制リダイレクト
    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    

    注意点:FilesMatchとDirectoryの違い

    よくある間違いとして、FilesMatch でパスを指定しようとするケースがあります。

    # ❌ 意図した動作にならない
    <FilesMatch "^wp-includes/.*\.json___PRE_BLOCK_7___quot;>
      Require all denied
    </FilesMatch>
    

    FilesMatch はファイル名にしかマッチしないため、wp-includes/ の部分は無視されます。この書き方では「主要なJSONファイル」が対象になってしまいます。

    特定ディレクトリを対象にしたい場合は <Directory> ブロックを使います。ただし、<Directory> はサーバーの絶対パスを記述する必要があるため、.htaccess では使いにくい場面もあります。

    まとめ:完成版 .htaccess

    上記の設定をまとめた .htaccess のテンプレートです(WordPressのルートディレクトリに設置するケースを想定しています)。

    # WordPress重要ファイルへのアクセス制限
    <FilesMatch "^(wp-config\.php|.*\.(hta)|wp-mail\.php|install\.php|xmlrpc\.php)___PRE_BLOCK_8___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    
    # WordPressのバージョン情報漏洩防止
    <FilesMatch "^(readme\.html|license\.txt)___PRE_BLOCK_8___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    
    # ディレクトリリスティング防止
    Options -Indexes
    
    # REST APIへのアクセス制限(認証済みユーザーのみ許可)
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteCond %{REQUEST_URI} ^/wp-json/(.*)$ [NC]
      RewriteCond %{HTTP_COOKIE} !wordpress_logged_in [NC]
      RewriteRule ^(.*)$ - [R=403,L]
    </IfModule>
    
    # バックアップファイルやログファイルの保護
    <FilesMatch "\.(bak|log|sql|tar|gz|zip)___PRE_BLOCK_8___quot;>
      Order Allow,Deny
      Deny from all
      Require all denied
    </FilesMatch>
    
    # セキュリティヘッダー設定
    <IfModule mod_headers.c>
      Header set X-XSS-Protection "1; mode=block"
      Header set X-Content-Type-Options "nosniff"
      Header set X-Frame-Options "SAMEORIGIN"
      Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
      Header set Referrer-Policy "strict-origin-when-cross-origin"
      Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
    </IfModule>
    
    # wp-includes内のPHPを直接実行禁止
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteBase /
      RewriteRule ^wp-admin/includes/ - [F,L]
      RewriteRule !^wp-includes/ - [S=3]
      RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
      RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
      RewriteRule ^wp-includes/theme-compat/ - [F,L]
    </IfModule>
    
    # HTTPS強制リダイレクト
    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    
    # GZIP圧縮
    <IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
    SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
    SetEnvIfNoCase Request_URI _\.utxt$ no-gzip
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/atom_xml
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/x-httpd-php
    </IfModule>
    
    # BEGIN WordPress
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
      RewriteBase /
      RewriteRule ^index\.php$ - [L]
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteRule . /index.php [L]
    </IfModule>
    # END WordPress
    

    BEGIN WordPressEND WordPress の間は触らないこと。 WordPressが自動更新するブロックです。セキュリティ設定は必ずこのブロックのに記述します。

    さらに強固にするには

    .htaccess の設定に加えて、以下もあわせて行うとより安全です。

    • ログインURLの変更(デフォルトの wp-login.php を非公開にする)
    • ログイン試行の制限(Solid Security などのプラグインで)
    • プラグイン・テーマの定期更新(脆弱性の多くは古いバージョンに起因)
    • 不要なプラグインの削除(無効化だけでは不十分、完全削除を)

    これらの対策については、別記事で詳しく解説します。