WordPressのセキュリティ 制作者向け基本ガイド

## はじめに

過去にWordPressの脆弱性に関するケーススタディをご紹介しました。

- [Webアプリケーションの脆弱性ケーススタディ（WordPress編）](https://qiita.com/prograti/items/951949e407fe8a40043b)
- [Webアプリケーションの脆弱性ケーススタディ（WordPress編その２）](https://qiita.com/prograti/items/82409213bb875540a52e)

今回はWordPressのセキュリティ対策を行う上で大切な基本事項をまとめてみたいと思います（本記事はWordPress 4.9.4をもとに書いております。古いバージョンと異なる部分があるかもしれませんので予めご了承ください）。

### :white_check_mark: WordPress本体およびプラグインやテーマのアップデートを行う

WordPress3.7以降では初期状態でマイナーバージョンの自動アップデートが有効になっています（1日に2回WP-Cronイベントで更新チェックが行われます）。つまり、バグフィックスやセキュリティパッチなどは自動的に適用されているわけですが、WordPressサポートチームは常に最新版を使用するように推奨しています。

参考：Supported Versions
https://codex.wordpress.org/Supported_Versions

>The only current officially supported version is WordPress 4.9.2. Previous major releases before this may or may not get security updates as serious exploits are discovered. 

>WordPress will be backported security updates when possible, but there are no guarantee and no timeframe for older releases. There are no fixed period of support nor Long Term Support (LTS) version such as Ubuntu's. None of these are safe to use, except the latest series, which is actively maintained. 

最新のメジャーバージョンにアップデートしていない場合はできる限り最新版にアップデートするようにしてください。もし、メジャーバージョンも自動アップデートしたいのであれば、`allow_major_auto_core_updates`フィルタを利用することでメジャーバージョンも含めることができます。

```functions.php
add_filter('allow_major_auto_core_updates', '__return_true');
```

もしくはwp-config.phpに以下の定数を定義する方法もあります。

```wp-config.php
define('WP_AUTO_UPDATE_CORE', true);
```

プラグインやテーマは基本的には自動アップデートの対象外になります。 [^1]
管理画面から手動でアップデートするか、もし自動アップデートしたいのであれば、`auto_update_plugin`フィルタと`auto_update_theme`フィルタを利用してください。

```functions.php
add_filter('auto_update_plugin', '__return_true');
add_filter('auto_update_theme', '__return_true');
```

:warning: 自動アップデートでサイトに不具合が出る可能性もありますので、定期的にバックアップを取ることをお勧めいたします。

### :white_check_mark: wp-config.phpについて理解する・カスタマイズする

wp-config.phpはインストール時に自動的に設定されるので、DB接続情報以外は意識することは少ないかもしれません。しかし、重要なファイルの一つですので、いくつかポイントをまとめてみたいと思います。

:one: **認証用ユニークキー**

DB接続情報を設定する箇所の下に認証用ユニークキーを設定する箇所があります。

```wp-config.php
define('AUTH_KEY',         'put your unique phrase here');
define('SECURE_AUTH_KEY',  'put your unique phrase here');
define('LOGGED_IN_KEY',    'put your unique phrase here');
define('NONCE_KEY',        'put your unique phrase here');
define('AUTH_SALT',        'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT',   'put your unique phrase here');
define('NONCE_SALT',       'put your unique phrase here');
```

認証用ユニークキーは以下のURLから発行できるのは周知のとおりだと思います。
https://api.wordpress.org/secret-key/1.1/salt/

では、この認証用ユニークキーはどういう役割を果たしているのかご存知でしょうか:thinking:

WordPressではログインすると認証CookieとログインCookieの2種類が作成されます。Cookieに書きこまれる情報はユーザーIDとパスワードの一部、Cookieの有効期限、ランダム文字列（トークン）などを組み合わせて[hash_hmac](http://php.net/manual/ja/function.hash-hmac.php)関数を使ってハッシュ化し、そこにさらにデータを付加して再度hash_hmac関数でハッシュ化したものになります。このハッシュ化の際に使用される秘密鍵がAUTH_KEYとAUTH_SALT（SSLの場合はSECURE_AUTH_KEYとSECURE_AUTH_SALT）およびLOGGED_IN_KEYとLOGGED_IN_SALTになります。

ユーザーのログイン状態をチェックする時は認証CookieによるチェックとログインCookieによるチェックのダブルチェックを行っています（おそらくCookieを偽装しにくくするため）。NONCE_KEYとNONCE_SALTはnonce（CSRF対策として使われている）を生成するために利用されます。

もしかすると、インストール時に認証用ユニークキーを設定していないという方もいらっしゃるかもしれません。でも、ちゃんとCookieに書き込まれる情報はハッシュ化されます。なぜなら、この認証用ユニークキーはインストール時にDBにも作成されており、wp-config.phpに設定がない場合はDBにある認証用ユニークキーが利用されるからです。

では、何ためにwp-config.phpで設定できるようになっているのでしょうか。ユースケースとして一つ考えられるのは、不正アクセスや何らかのミスで認証用ユニークキーが漏洩してしまった場合です。認証用ユニークキーが分かればCookieを偽装してブルートフォース攻撃をすることも決して難しいことではありません。認証用ユニークキーが漏洩した可能性がある場合は認証用ユニークキーを変更した方が安全でしょう。

それ以外にも、もしユーザー全員のログイン状態（自動ログインも含めて）をクリアしたいケースがあった場合、ユーザー全員のパスワードを変更するのは大変です。そのような場合は認証用ユニークキーを変更すればログイン状態をクリアできます。


:two: **データベーステーブルの接頭辞**

WordPressに作成されるデータベーステーブルの接頭辞は初期状態で"wp_"となっています（共有サーバの場合は既に変更されていると思います）。

```wp-config.php
$table_prefix  = 'wp_';
```

接頭辞は複数のWordPressを入れても競合しないように提供されているものですが、セキュリティの観点から変更した方が良いと言う方も多くいらっしゃいます。変更することに異論はありませんが、変更したから安全だとは決して考えない方が良いでしょう。

攻撃者が任意のクエリを実行できる状態にあった場合、テーブルの一覧や接頭辞を知ることは難しくありません。

```sql
-- テーブルの一覧を表示
SHOW TABLES;

-- テーブルの接頭辞を表示
SELECT DISTINCT SUBSTRING(`TABLE_NAME` FROM 1 FOR ( LENGTH(`TABLE_NAME`)-8 ) ) 
FROM information_schema.TABLES WHERE 
`TABLE_NAME` LIKE '%postmeta';
```

接頭辞の変更で過信せずに、それ以外のセキュリティ対策も十分に行ってください。

テーブル関連でいうと、WordPressではユーザー情報のテーブル名をwp_users、wp_usermetaから任意の名前に変更することもできます。変更したからセキュリティが高まるとは言い難いのですが、もし変更したい場合は`CUSTOM_USER_TABLE`と`CUSTOM_USER_META_TABLE`をwp-config.phpに定義してください。

```wp-config.php
define('CUSTOM_USER_TABLE', $table_prefix.'hoge');
define('CUSTOM_USER_META_TABLE', $table_prefix.'hogemeta');
```

:three: **テーマエディタおよびプラグインエディタを無効にする**

WordPressの管理画面にはエディタ上でテーマを編集する機能とプラグインを編集する機能が標準で用意されています。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/05a7cecc-d570-7a5b-f2e6-ab46371368ed.jpeg)

ちょっと修正したい時に便利な機能なのですが、この機能が有効になっていると不正アクセスされた場合に簡単にバックドアを仕込むことができてしまいます。基本的にこの機能は無効にしてローカルで編集したファイルをSFTPでアップロードするようにした方が安全です。無効にするにはwp-config.phpに以下の記述を追加すればOKです。

```wp-config.php
define('DISALLOW_FILE_EDIT', true);
```

:warning: `current_user_can('edit_plugins')`を使用しているプラグインがあった場合、上記操作により動作しなくなる可能性があります。


なお、`DISALLOW_FILE_EDIT`とは別に`DISALLOW_FILE_MODS`というのもあります。こちらはファイルの編集に加えて画面からプラグインやテーマのインストールおよびアップデートも禁止にすることができます。不正なプラグインをインストールされないようにするなら、こちらの方がより強固かもしれません。

```wp-config.php
define('DISALLOW_FILE_MODS', true);
```

ただし、これだとWordPress本体も含めて全ての自動アップデートが無効になってしまうため、もし自動アップデートを有効にしたいのであればfunctions.phpにフィルタを追加してください。

```functions.php
add_filter('file_mod_allowed', function($allowed, $context) {
  return 'automatic_updater' === $context;
}, 10, 2);
```

:four: **wp-config.phpをプロテクトする**

本番公開後にwp-config.phpを編集する機会はほとんどありません。ファイルのパーミッションを**400**などの読み取り権限のみに変更して、編集する時だけ書き込み権限を付与した方が安全です。ファイルの編集はローカルPCで行うようにしましょう。なぜなら、オンラインで編集する場合、エディタによってはswp（スワップ）ファイルを作成するものがあり、そこにアクセスされる可能性があるからです。

また、サーバーで何らかの作業をしていて、ちょっとした設定ミスでphpファイルがテキストで表示されてしまうことも稀にあります。そのような場合も考慮して.htaccessに以下の記述を追加して、wp-config.phpへのアクセスを禁止すると良いでしょう。

```apache
# Apache 2.2
<Files wp-config.php>
  order allow,deny
  deny from all
</Files>

# Apache 2.4
<Files wp-config.php>
  Require all denied
</Files>
```

もしくは、wp-config.phpをルートの外に移動させてしまう方法もあります。例えば以下のようにルートのwp-config.phpは移動先のwp-config.phpを読み込むだけにする形です。

```wp-config.php
<?php
require_once(dirname(__FILE__) . '/' . '../path/to/wp-config.php');
```

なお、WordPressはルートにwp-config.phpがない場合は一つ上の階層を探しに行き、そこにwp-config.phpがあればそれを読み込んでくれますので、その機能を利用することもできます。

:five: **プラグインディレクトリを移動する**

アクセスログを見るとプラグインのphpファイルに直接リクエストが来ていることがよくあります。

```http
GET /wp-content/plugins/wp-db-ajax-made/xml_rpc.class.php HTTP/1.1
```

これは脆弱性のあるプラグインやウィルスを含むプラグインを狙った攻撃なのですが、Remote Code ExecutionやArbitrary File Downloadのような脆弱性のあるプラグインは過去に数多く報告されています。

このような自動スクリプトによる攻撃を防ぐ方法の一つとしてプラグインディレクトリを移動する方法があります。プラグインディレクトリは`WP_PLUGIN_DIR`という定数で定義されていますので、wp-config.phpで以下のように任意の場所に変更することができます。

```wp-config.php
define('WP_PLUGIN_DIR', dirname(__FILE__) . '/extensions/');
```

:warning: CSSやJavaScriptの読み込みに失敗して上手く動作しなくなるプラグインもありますのでご注意ください。

### :white_check_mark: .htaccessにルールを追加する

.htaccessはセキュリティを高める上で手軽に利用できる方法の一つです。いくつかポイントをご紹介したいと思います。

:one: **wp-adminへのアクセスを制限する**

管理画面はログイン認証があるとはいえ、ブルートフォース攻撃などで破られる可能性があります。また、最近だと`wp-admin/load-scripts.php`に直接リクエストを送ってサーバに負荷を掛けることができるといった報告も挙がっています。

https://www.cvedetails.com/cve/CVE-2018-6389/

したがってwp-adminは可能な限りアクセスを制限した方が安全です。

もし、特定のIPアドレスからしかアクセスしないのであれば.htaccessでIP制限をかけましょう。まずwp-login.phpにIP制限をかけるためにルートにある.htaccessに以下のような内容を記述します。

```apache
# Apache 2.2
<Files wp-login.php>
  order deny,allow
  deny from all
  allow from 192.168.33.10
</Files>

#Apache 2.4
<Files wp-login.php>
  Require all denied
  Require ip 192.168.33.10
</Files>
```

次にwp-adminディレクトリの直下に.htaccessを作成し、以下のような内容を記述します。なお、ここではAjaxリクエストを許可していますが、プラグインなどでAjaxを使用しないのであれば不要です。

```apache
# Apache 2.2
order deny,allow
deny from all
allow from 192.168.33.10

<Files admin-ajax.php>
  Order allow,deny
  Allow from all
  Satisfy any 
</Files>

# Apache 2.4
Require all denied
Require ip 192.168.33.10

<Files admin-ajax.php>
  Require all granted
</Files>
```

もしIPアドレスでの制限が難しいのであれば代わりにBasic認証を検討してください。

```apache
<Files wp-login.php>
  AuthType Basic
  AuthName "Restricted"
  AuthUserFile /path/to/.htpasswd
  Require valid-user
</Files>
```

```apache
AuthType Basic
AuthName "Restricted"
AuthUserFile /path/to/.htpasswd
Require valid-user

# Apache 2.2
<Files admin-ajax.php>
  Order allow,deny
  Allow from all
  Satisfy any 
</Files>

# Apache 2.4
<Files admin-ajax.php>
  Require all granted
</Files>
```

なお、apacheのhttpd.confには最初から.htaccessや.htpasswdへのアクセスをブロックするように設定されていると思いますが、もし設定されていないのであれば追加した方が良いでしょう。

```apache:httpd.conf
<Files ".ht*">
  Require all denied
</Files>
```

:two: **wp-includeへのアクセスを禁止する**

wp-includeフォルダ配下にあるphpスクリプトはWordPressのコアファイルであり、通常はincludeされて使われるもので直接アクセスされることはありません。直接アクセスされても何も出力されない場合がほとんどなのですが、一部のファイルは`display_errors`が有効になっているとエラー情報が出力されてしまいます。攻撃者に余計な情報を与えるのは望ましくありませんので、アクセス禁止にしてしまった方が安全です（マルチサイトの場合は`wp-includes/ms-files.php`はアクセス許可にする必要があります）。

```apache
<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>
```

:three: **アップロードフォルダでPHPスクリプトが実行できないようにする**

プラグインの脆弱性などによりPHPスクリプトがアップロードされてしまうケースはたびたび起こります。アップロードフォルダ（`wp-content/uploads`）直下に.htaccessを作成して、仮にアップロードされたとしても実行できないようにした方が安全です。

```apache
# Apache 2.2
<FilesMatch "\.php$">
   deny from all
</FilesMatch>

# Apache 2.4
<FilesMatch "\.php$">
   Require all denied
</FilesMatch>

# .php5や.phtなどもブロックする場合
<FilesMatch "\.ph(?:p[345]?|t|tml)$">
   Require all denied
</FilesMatch>
```

もし、アップロードできるファイルの種類を限定できるのであればそれだけを許可した方がより安全かもしれません。

```apache
Require all denied

<FilesMatch "\.(jpg|jpeg|png|gif)$">
  Require all granted
</FilesMatch>
```

:four: **XML-RPCを無効にする**

XML-RPCはモバイルアプリから投稿する場合など外部連携のためのAPIとして使用されていますが、pingbackによるDDosやブルートフォース攻撃に悪用されやすい機能です。XML-RPCを使用していないのであれば無効にした方が安全です。

```apache
# Apache 2.2
<Files xmlrpc.php>
  Order Allow,Deny
  Deny from all
</Files>

# Apache 2.4
<Files xmlrpc.php>
  Require all denied
</Files>
```

もしくはフィルタを使って無効にすることもできます。

```functions.php
add_filter('xmlrpc_enabled', '__return_false');
```

また、XML-RPCと同様の機能にWP REST APIがあります。こちらを無効にする場合はリライトルールを追加します。

```
RewriteRule ^wp-json(.+) - [F,L]
```

もしくはフィルタを使って無効にすることもできます。

```functions.php
add_filter('rest_authentication_errors', function(){
  return new WP_Error('403', 'Forbidden');
});
```

:warning: Contact Form 7やJetpackといったプラグインはREST APIを使用しているため無効にすると不具合が発生します。ご注意ください。

### :white_check_mark: ユーザー認証を強固にする

IPアドレスでの制限やBasic認証などの方法は前述しましたが、ここではそれ以外の方法をいくつかご紹介します。（敢えて言う必要はないかと思いますが、パスワードは大文字、小文字、数字、記号を使って強度のあるものにしてください）

:one: **2段階認証を使う**

最近は2段階認証を提供するWebサービスも多くなりましたが、WordPressでもプラグインを使えば簡単に2段階認証を利用することができます。ここでは、[miniOrange 2 Factor Authentication](https://wordpress.org/plugins/miniorange-2-factor-authentication/)というプラグインを使ってみたいと思います。

プラグインをインストールしてminiOrangeにアカウントを作成するとすぐに2段階認証が利用できるようになります。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/4dc2f37f-ebb4-70c6-6142-e1b9251eebe8.jpeg)

無料プランでも色々な方式を利用できますが、一番簡単なEメール認証を使ってみたいと思います。まずログイン画面で普通にログインします。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/4572ca4a-394e-f996-eb09-b11414e3c83a.jpeg)

そうすると以下のような画面が表示され承認が終わるまで待機し続けます。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/b9bae214-f16f-3f2b-3efc-5164e41616a3.jpeg)

メールを確認すると以下のようなメールが届いていますので記載されているリンクをクリックします。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/9f862b45-b3bb-6c94-e9bd-4f3df90a1d78.jpeg)

以下のような画面が表示され、先程の画面に戻るとログインして管理画面が表示されています。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/65893925-86a6-57ab-8553-e92026956a9e.jpeg)

このように非常に簡単に2段階認証を利用することができます。なお、このプラグインは無料で利用できますがユーザー数は1人までとなっています（有料プランもあり）。

:two: **CAPTCHAを使う**

2段階認証は非常に強固ですが、無料だと制限があったりして実運用に適さない場合があるかもしれません。ボットによる不正アクセスを防ぐという点においてはCAPTCHAが有効であると言われています。ここでは[Advanced noCaptcha reCaptcha](https://wordpress.org/plugins/advanced-nocaptcha-recaptcha/)というプラグインを使ってGoogleのreCaptchaを設置してみたいと思います。

プラグインをインストールして設定画面を開くとreCaptchaを利用するためのサイトキーとシークレットキーを入力する欄がありますので、Googleのサイトで発行したキーを入力し、設定を保存してください。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/941f2cd8-f859-31b0-57a6-fec8271b7dde.jpeg)

キーを発行して間もないとまだreCaptchaがサイトのドメインを認識していなくて表示されない場合がありますので、10分くらい待ってログイン画面にアクセスします。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/c5f6c5e9-cb99-ab07-576a-dd6a0e3a74ce.jpeg)

そうするとログインフォームにreCaptchaが表示されます。これで設定は完了です。CAPTCHA自体が完璧な仕組みであるとは言えませんが、ユーザー数などの制限もなく容易に導入できますので検討してみてください。

:three: **ログイン試行回数を制限する**

ログインの試行回数を制限すれば手当たり次第にログインを試みるブルートフォース攻撃を防ぐことができサイトの安全性を高めることができます。ここでは[WP Limit Login Attempts](https://wordpress.org/plugins/wp-limit-login-attempts/)というプラグインを使ってみたいと思います。このプラグインは無料版だと初期設定は変更できませんでの、インストールするだけで完了です。

試しにわざとログインに失敗してみると以下のようなメッセージが表示されます。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/63b99e10-a0de-ecbc-a067-f394edb12e22.jpeg)

5回連続で失敗すると以下のようなメッセージが表示され、10分間同一IPアドレスからログインできなくなります。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/49809d57-0f8f-a388-4813-5afd7963d78a.jpeg)

初期設定を変更できない不便さはありますが、他にも同様のプラグインはあると思いますので導入を検討してみてください。

:four: **ログイン画面、管理画面のURLを変更する**

ログイン画面や管理画面のURLが`wp-login.php`や`/wp-admin/`のままだとボットによる不正アクセスを受けやすくなります。.htaccessにRewriteRuleを追加して変更すればそのようなアクセスを軽減することができます。

```apache
<IfModule mod_rewrite.c> 
  RewriteEngine On 
  RewriteBase / 

  RewriteRule ^hello-login.php(.*) /wp-login.php$1 [L,QSA]
  RewriteCond %{ENV:REDIRECT_STATUS} ^$
  RewriteRule ^wp-login.php - [F,L]

  RewriteCond %{REQUEST_URI} /hello-admin$
  RewriteRule ^(.*)$ /hello-admin/ [R=301,L]
  RewriteRule ^hello-admin(.*) /wp-admin$1 [L,QSA]
  RewriteCond %{ENV:REDIRECT_STATUS} ^$
  RewriteRule ^wp-admin(.+) - [F,L]
</IfModule> 
```

もし、管理画面からしかユーザー追加を行わないのであればwp-signup.phpとwp-activate.phpもブロックしておくと良いでしょう。

```apache
RewriteRule ^wp-signup.php - [F,L]
RewriteRule ^wp-activate.php - [F,L]
```


### :white_check_mark: セキュリティプラグイン、WAFを導入する

PCにウィルス対策ソフトを入れるのと同じようにWordPressにも外部からの脅威を防御するためのセキュリティプラグインやWAF（web application firewall）が存在します。もし、AWSを利用しているのであればマーケットプレイスで複数のセキュリティベンダがWAFを提供していますので、そちらを利用すると良いでしょう。

AWS WAF のマネージドルール
https://aws.amazon.com/jp/mp/security/WAFManagedRules/

AWS WAF の料金
https://aws.amazon.com/jp/waf/pricing/?p=ps

ここでは個人的によく利用しているWordPressプラグインの[Wordfence Security](https://wordpress.org/plugins/wordfence/)を簡単にご紹介したいと思います。

![tmp.jpg](https://qiita-image-store.s3.amazonaws.com/0/184074/efcc360d-0dc8-a08e-3186-d67df248fd3b.jpeg)

Wordfenceが提供してくれる機能は主に以下の4つです。

- 外部からの攻撃を防ぐFirewall機能
- 特定の条件に基づいてアクセスをブロックするBlocking機能
- 悪意のあるコードやバックドアを検知するScan機能
- その他Tools

:one: **Firewall機能**

外部からのリクエストに対してルールに基づきパターンマッチングを行い、攻撃とみなされるリクエストをブロックします。主に以下のような攻撃に対応しています。

- SQL Injection
- Cross Site Scripting (XSS)
- Malicious File Upload
- Directory Traversal
- Local File Inclusion
- External Entity Expansion (XXE)

Firewallのルールはネットワークを通じて自動的に更新されます。ただし、有料版だと逐一リアルタイムで更新されますが、無料版の場合は有料版の30日後になります。インストール後すぐにルールを適用するか、もしくは一定期間学習モードでサイトのアクセスパターンを覚えさせ、そこからルールを適用することもできます（誤検知を防ぐため）。

また、防御モードにベーシックと拡張の2種類を選択することができます。ベーシックモードはプラグインとして起動しリクエストを防御します。しかし、Wordfenceが起動する前に別のプラグインが起動するとそちらは防御対象外になります。また、PHPファイルにダイレクトにリクエストされるとプラグインは起動しませんので、そちらも防御対象外になります。

拡張モードはサーバの設定状況を見て、必要に応じて.htaccessや.user.ini、php.iniなどを変更し、全てのリクエストに対して可能な範囲で防御するモードになります。

:two: **Blocking機能**

以下のブロック機能を提供します。

- 指定したIPアドレスのブロック（ホワイトリストの作成も可能）
- 国レベルでのIPアドレスのブロック
- ユーザーエージェントを用いたブロック
- リファラーを用いたブロック
- 上記複数の条件を組み合わせたブロック

:three: **Scan機能**

WordPress内の全てのファイルをスキャンし悪意のあるコードやバックドア、シェルなどが攻撃者によってインストールされていないかどうかをチェックします。また、投稿、固定ページ、コメント内に不正なコードやURLが埋め込まれていないかどうかもチェックします。

スキャンする項目やスケジュールは自由にカスタマイズできます。ほとんどの項目は無償版でもスキャンできますが、一部の項目（Spamvertising Check、Spam Check、Blacklist Check）は有償版のみとなります。

スキャンが完了すると結果が管理画面に表示され、削除を行うか無視するかを選択することができます。

:four: **その他Tools**

- ユーザーのパスワードの強度をチェックする機能（有料版のみ）
- コメントスパムのフィルタリング機能
- サーバの設定内容をチェックする機能
- 直近のアクセスを確認できるライブトラフィック機能
- 2段階認証機能（有料版のみ）

以上が簡単なWordfenceの機能紹介になります。本プラグインに限らず他のセキュリティプラグインも同様の機能を提供してくれると思いますので、必要に応じてベンダーに問い合わせるなどして要件にあった製品をお探しください。**セキュリティプラグイン・WAFの導入を強くお勧めいたします**。

### :white_check_mark: その他Tips

:one: **ファイル・ディレクトリのパーミッションを適切に設定する**

共有サーバをご利用の場合は、サーバ運営会社が推奨する設定値がサポートページなどに記載されていると思いますので、そちらを参照して頂きたいのですが、一般的な共有サーバだと以下のように必要最小限の権限を与える形になります。

|ファイル|パーミッション||
|:--|:--|:--|
|ディレクトリ|705|rwx---r-x|
|wp-config.php|400|r--------|
|PHPファイル|600|rw-------|
|HTML、CSS、画像など|604|rw----r--|
|.htaccess|604|rw----r--|

お使いの共有サーバによってはディレクトリが755だったり、ファイルが644かもしれません。推奨値に従ってください。ディレクトリを777に設定したり、ファイルを666に設定したりすると共有サーバの別のユーザからファイルを改ざんされる可能性がありますので十分にご注意ください。

:two: **不要なプラグイン・テーマを削除する**

**プラグインやテーマで使用していないものは必ず削除してください**。仮に無効にしていたとしても、プラグインに脆弱性があるとファイルに直接アクセスされてコマンドを実行されたり、ファイルをアップロード・ダウンロードされる可能性があるからです。

:three: **WordPressのバージョン情報を削除する**

WordPressのバージョン情報は攻撃者が参考する情報の一つです。WordPressは初期状態ではメタタグなどにバージョン情報が出力されます。

```html
<meta name="generator" content="WordPress 4.9.4" />
```

削除したから攻撃されないというわけではありませんが、念のため削除しておいた方が無難です。functions.phpに以下の内容を記述してください。

```functions.php
add_filter('the_generator', '__return_empty_string');
```

ネット上では下の方をよく見かけますが、これだとRSSとかにはバージョン情報が表示されてしまいますので上のフィルタの方が良いかと思います。

```functions.php
remove_action('wp_head', 'wp_generator');
```

加えて、CSSやJavaScriptからもバージョン情報を削除したり、readme.htmlやlicense.txtをブロックしておくと良いでしょう。

```functions.php
function remove_wp_version_str($src) {
  global $wp_version;
  parse_str(parse_url($src, PHP_URL_QUERY), $query);
  if (!empty($query['ver']) && $query['ver'] === $wp_version) {
    $src = remove_query_arg('ver', $src);
  }
  return $src;
}

add_filter('script_loader_src', 'remove_wp_version_str');
add_filter('style_loader_src', 'remove_wp_version_str');
```

```apache
<Files readme.html>
  Require all denied
</Files>
<Files license.txt>
  Require all denied
</Files>
```


:four: **しっかり検討した上でプラグインやテーマをインストールする**

プラグインやテーマにバックドアが仕込まれるサプライチェーンアタックがたびたび発生しています。

- [Three More WordPress Plugins Found Hiding a Backdoor](https://www.bleepingcomputer.com/news/security/three-more-wordpress-plugins-found-hiding-a-backdoor/)
- [Backdoor in Captcha Plugin Affects 300K WordPress Sites](https://www.wordfence.com/blog/2017/12/backdoor-captcha-plugin/)
- [WordPress Plugin Banned for Crypto Mining](https://www.wordfence.com/blog/2017/11/wordpress-plugin-banned-crypto-mining/)

プラグインやテーマはWordPress公式レポジトリや運営がしっかりしているサイトなど信頼できるところからダウンロードするようにしてください。

WordPress公式レポジトリ
https://wordpress.org/themes/
https://wordpress.org/plugins/

テーマやプラグインのマーケットプレイス
https://themeforest.net/
https://www.elegantthemes.com/
https://codecanyon.net/category/wordpress

プラグインやテーマを選定するときは見た目や機能だけでなく、以下のような点も考慮するようにしましょう。

- 法人でサポート窓口がちゃんとあるかどうか
- 個人の場合、サポートのスレッドを見てユーザーの質問に丁寧に対応しているかどうか
- バクフィックスやセキュリティアップデート、機能改善などがこまめに行われているかどうか

あと、個人的な主観ですが、プラグインやテーマで利用されるCSSやJavaScriptがプラグインのアセットの中に含まれずに外部リソースから読み込まれているものは極力避けた方が良いかと思います（作成者が自由に悪意のあるコードに変更できるため）。

:five: **脆弱性情報をこまめにチェックする**

公式サイトにセキュリティアップデートなどの情報が掲載されますのでこまめにチェックしましょう。また、脆弱性データベースでプラグインやテーマの脆弱性情報が確認できますので、こちらもあわせてチェックしましょう。

公式サイト
https://wordpress.org/news/

脆弱性データベース
https://wpvulndb.com/

## まとめ

基本的な内容ばかりでしたが意外と見落としもあるかなと思ったのでまとめてみました。今回はWordPressの設定が中心でしたが、当然ながらカスタマイズの際のプログラミングにおける注意点などセキュリティで考慮すべき点は数多く存在します。既にご覧になっている方も多いと思いますが、IPAの「安全なウェブサイトの作り方」をご一読ください。

安全なウェブサイトの作り方
https://www.ipa.go.jp/security/vuln/websecurity.html

仕事の関係で様々なWordPressのサイトを触る機会がありますが、残念ならが100%と言っても過言ではないくらいほとんどのサイトがアップデートもまともに行われていないのが実情です。保守契約を結んでいないなど事情はあると思いますが、きちんとクライアントにセキュリティリスクを理解してもらった上で、継続的なメンテナンスができる状態にすることが制作に関わるディレクターや開発者の果たすべき役割だと思います。本記事が少しでもお役に立てれば幸いです。


[^1]: プラグインでも影響が深刻な場合はWordPressサポートチームの判断によって自動アップデートされることがあります。 ex) https://yoast.com/wordpress-seo-security-release/