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.html や license.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 WordPress~END WordPressの間は触らないこと。 WordPressが自動更新するブロックです。セキュリティ設定は必ずこのブロックの上に記述します。
さらに強固にするには
.htaccess の設定に加えて、以下もあわせて行うとより安全です。
- ログインURLの変更(デフォルトの
wp-login.phpを非公開にする) - ログイン試行の制限(Solid Security などのプラグインで)
- プラグイン・テーマの定期更新(脆弱性の多くは古いバージョンに起因)
- 不要なプラグインの削除(無効化だけでは不十分、完全削除を)
これらの対策については、別記事で詳しく解説します。

