このドキュメントは、ユーザーとのインタラクションを伴わないWordPressを使用して開発されたWebアプリケーションに適していることを目的として作成されています。主に、企業のブランドページ、各種静的ビュー、採用ページなどのサイトを対象としています。
ユーザーが登録して自由にサイトを利用するオープンコミュニティのようなWebサイトでは、このドキュメントの一部が適用できない場合があります。その点を念頭に置いてお読みください。
このドキュメントには、WordPressのセキュリティ確保に必要な「すべての内容」は含まれていません。
ただし、このガイドに基づいたセキュリティリスク評価や脆弱性対応が可能なレベルまでの一般的かつ詳細な情報が含まれています。
もしこれが役立つと感じたら、さらなる改善を支援するために 「スター」🌟 をお願いします。
WordPressをインストールする際、セットアップ中に変更しない限り、デフォルトの管理者ユーザー名は「admin」です。 "admin"というアカウント名は広く知られているため、別の名前に変更する必要があります。 管理者ユーザー名として「admin」を使い続けると、攻撃者が「admin」を使ってブルートフォース攻撃を試み、WordPressサイトにアクセスする可能性があります。
攻撃者がWordPress管理者アカウントにアクセスすると、Webサイトを完全に制御できるようになります。 デフォルトのWordPress管理者ユーザー名は別の名前に変更する必要があります。
監査:
修正:
注意:
WordPressにはデフォルトで5つのユーザーロールがあります - 「管理者」、「編集者」、「投稿者」、「寄稿者」、「購読者」
これらのロールにより、適切な権限を割り当てることで、ユーザーがWebサイトで実行できるタスクを制御できます。 ユーザーロールと権限が適切に管理されていない場合、ユーザーが重要な機能に対して不要なアクセス権を取得し、重大なセキュリティリスクが生じる可能性があります。
監査:
修正:
注意:
WordPressには組み込みのユーザー登録機能があります。この機能はデフォルトで無効になっていますが、管理者が有効にすることができます。
この機能が有効になっている場合、誰でも登録してWordPress管理ダッシュボードにアクセスできる可能性があり、セキュリティ問題につながる可能性があります。 オープンコミュニティとして運用することを意図していないほとんどのWebサイトでは、ユーザー登録機能は不要であり、無効のままにしておく必要があります。
監査:
Webブラウザを使用する

curlを使用する
(response) HTTP/1.1 302 Moved Temporarily cache-control: no-cache, no-store, must-revalidate, max-age=0 content-type: text/html; charset=UTF-8 server: Apache content-length: 0 ... location: https://yourwordpress.com/wp-login.php?registration=disabled
**修復方法:**
- ユーザー登録が有効になっている場合は、無効にします。
- 「誰でも登録できる」のチェックを外します。

## 4. プラグインファイルエディタが無効になっていることを確認する
攻撃者がWordPress管理者アカウントに侵入した場合、ウェブサイトを完全に制御される可能性があります。
攻撃者は、組み込みの「エディタ」機能を通じてテーマやプラグインのコードを編集し、悪意のあるスクリプトをアップロードしたり、サイトを改ざんしたり、ユーザーにスパムを送信したりすることができます。
これらのエディタを介した一般的なハッキングには、SQLインジェクション、SEOスパムハッキング、日本語SEOスパムなどがあります。
**監査:**
- ファイルエディタが無効になっていることを確認します。
- 外観 > エディタ または プラグイン > プラグインエディタ からエディタにアクセスできるかどうかを確認します。
**修復方法:**
- ファイルエディタが有効になっている場合は、以下の手順で無効にします。
1. ファイルマネージャーまたはFTPを使用してwp-config.phpファイルにアクセスします。
2. wp-config.phpファイルを編集用に開きます。
3. ファイルの末尾までスクロールします(デフォルトのwp-config.phpを使用している場合)。
4. 次の行を見つけます。
`
/* これで編集は終了です! 楽しい公開を! */
`
5. この行の上に、次のコードを追加します。
`
define('DISALLOW_FILE_EDIT', true);
`
6. 変更を保存し、エディタを閉じます。
7. WordPressダッシュボードに戻り、エディタオプションが使用できなくなったことを確認します。
## 5. 未使用の不要なプラグインが非アクティブ化されていることを確認する
WordPressの多くの脆弱性は、プラグインのセキュリティ問題に起因します。
プラグインはオープンソースであるため、攻撃者が脆弱性を見つけて悪用しやすくなっています。
使用しているプラグインは常に最新の状態に保ち、未使用のプラグインは非アクティブ化して潜在的な悪用を防ぐことが重要です。
**監査:**
- 未使用の不要なプラグインが非アクティブ化されていることを確認します。
- 未使用および不要なプラグインが非アクティブ化されていることを確認します。
**修復方法:**
- 未使用の不要なプラグインを非アクティブ化するには、次の手順に従います。
**プラグインチェック - PCP を使用する:**
- PCP: https://wordpress.org/plugins/plugin-check
1. プラグインチェック(PCP)をインストールして有効化する:
- WordPress管理ダッシュボードに移動します。
- プラグイン > 新規追加 に移動します。
- 「プラグインチェック」を検索し、インストールして有効化します。
2. プラグインチェックを実行する:
- WordPressダッシュボードで、プラグインチェックメニューに移動します。
- チェックしたいプラグインを選択し、スキャンを実行します。
3. スキャン結果を分析する:
- PCPはプラグインのコードを分析し、次の内容を含むレポートを提供します。
- コード標準準拠: プラグインがWordPressコーディング基準にどの程度準拠しているか。
- セキュリティ問題: 潜在的な脆弱性や悪意のあるコード。
- パフォーマンス問題: ウェブサイトのパフォーマンスへの影響。
- 互換性問題: プラグインが他のプラグインやテーマと互換性があるかどうか。
4. 問題のあるプラグインを特定する:
- レポートで重大なセキュリティ脆弱性、悪意のあるコード、または多数のコーディング標準違反が強調表示されている場合、そのプラグインは「怪しい」可能性が高いです。
- 不要な外部リクエストを行ったり、過剰なデータベースクエリを実行するプラグインには注意してください。
5. 問題を解決する:
- 特定された問題を更新するか、プラグインページで問題を見つけて修正します。
- 深刻なセキュリティ問題があるプラグインの使用は避けてください。必要に応じて代替プラグインを見つけてください。
**プラグイン管理:**
1. プラグインの選択:
- 公式リポジトリを使用する、レビューと評価を確認する、開発者の信頼性を確認する。
- 未知の検証されていないプラグインは使用しないでください。
2. 定期的な更新
- 最新のセキュリティパッチを確実に適用するために、プラグインを最新の状態に保ちます。
3. 未使用のプラグインを非アクティブ化して削除する
- 非アクティブなプラグインでもセキュリティリスクとなる可能性があるため、使用しない場合は削除します。
- プラグインを最小限に抑える: 必要なプラグインのみを使用する
## 6. WordPress(WordPress管理画面を含む)がHTTPSのみを使用するように設定されていることを確認する
現在、ほとんどのウェブサイトはSSL(HTTPS)を介して動作するように設定されています。
ただし、一部のウェブサーバーは、HTTPとHTTPSの両方の接続を処理するように誤って設定されている場合があります。
これにより、両方のプロトコルを介してWordPressにアクセスできる可能性があり、セキュリティリスクとなります。WordPress管理画面を含むWordPressは、HTTPSのみを使用するように強制する必要があります。
**監査:**
- WordPress(WordPress管理画面を含む)がHTTPS経由でのみアクセス可能に設定されていることを確認します。
- ウェブサーバーのVirtualHost構成を確認し、HTTPのVirtualHostが設定されていないことを確認します。
**修復方法:**
- HTTPアクセスが可能な場合は、最初にウェブサーバーの設定を確認して変更します。
- サーバーにHTTP VirtualHostがある場合は、HTTPSにリダイレクトするか、HTTP VirtualHostを削除します。
- 必要に応じて、「FORCE_SSL_ADMIN」機能を有効にして、WordPress管理画面へのHTTPSアクセスを強制します。
**FORCE_SSL_ADMINを有効にする手順:**
1. ファイルマネージャーまたはFTPを使用してwp-config.phpファイルにアクセスします。
2. wp-config.phpファイルを編集用に開きます。
3. ファイルの末尾までスクロールします(デフォルトのwp-config.phpを使用している場合)。
4. 次の行を見つけます。
`
/* これで編集は終了です! 楽しい公開を! */
`
5. この行の上に、次のコードを追加します。
`
define('FORCE_SSL_ADMIN', true);
`
6. 変更を保存し、エディタを閉じます。
WordPressダッシュボードに戻り、WordPress管理画面がHTTPS経由でのみアクセス可能であることを確認するために再度ログインします。
**ウェブサーバーでHTTPからHTTPSにリダイレクトする:**
1. Apacheの場合:
```
<VirtualHost *:80>
ServerName yourwordpress.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>
```
2. Nginxの場合:
```
server {
listen 80;
server_name yourwordpress.com;
location / {
return 301 https://$host$request_uri;
}
}
```
WordPressとWordPress管理画面がHTTPS経由でのみアクセス可能になるようにすることで、ウェブサイトのセキュリティを大幅に向上させ、データを保護し、不正アクセスを防止できます。
## 7. IPアクセス制限(ACL)が適用されていることを確認する
IPアクセス制限が適用されていることを確認します。
WordPressを安全に運用するには、WordPress管理画面を含む特定のURLにIPアクセス制限を適用し、不要なユーザー、コンピューター、ボットからのアクセスを防ぐことが不可欠です。これには、管理者IPなどの許可されたIPアドレスからのみアクセスを許可することが含まれます。さらに、攻撃対象領域を最小限に抑えるために、未使用の機能を無効にする必要があります。
保護すべきURLには、WordPress管理画面、ユーザー登録(wp-signup.php)、JSON REST API、XML-RPC機能が含まれます。
このセキュリティガイドは、ユーザーとのやり取りが最小限でコンテンツが主に表示される、企業ブログ、採用ページ、ブランドサイト、プロモーションサイトなどのサービス指向のウェブサイトを対象としています。
IPアクセス制限を実装することで、不正アクセスのリスクを大幅に削減し、ウェブサイト全体のセキュリティを強化できます。
### 7.1. WordPress管理画面にIPアクセス制限が適用されていることを確認する。
WordPress管理画面のアクセスパスはwp-login.phpまたは/wp-adminという形式で固定されており、不正ユーザーが簡単にアクセスできるようになっています。
管理ページへの不正アクセスを防ぐために、IPアクセス制限が適用されていることを確認します。
**監査:**
- WordPress管理画面にIPアクセス制限が適用されていることを確認します。
- ほとんどの場合、これはウェブサーバー(Apache、Nginx)で設定されます。
**修復方法:**
- IPアクセス制限が適用されていない場合は、実装します。
- 以下は、ApacheおよびNginxウェブサーバーを使用してIPアクセス制限を適用する方法です。
**WordPress管理画面にIPアクセス制限を適用する:**
- /wp-admin, wp-login.php
1. Apacheの場合:
```
# Files ディレクティブ
<Files "wp-login.php">
Require ip 10.10.77.49 # あなたのIPアドレスに置き換えてください
</Files>
# FilesMatch ディレクティブ
<FilesMatch "^wp-login\.php$">
Require all granted
</FilesMatch>
# Directory, Files 混合ディレクティブ
<Directory /www/vhosts/yourwordpress>
Require all granted
AllowOverride None
<Files "wp-login.php">
Require ip 10.10.77.49 # あなたのIPアドレスに置き換えてください
</Files>
</Directory>
# Location ディレクティブ
<Location "/wp-admin">
Require ip 10.10.77.49 # あなたのIPアドレスに置き換えてください
</Location>
<Location "/wp-login.php">
Require ip 10.10.77.49 # あなたのIPアドレスに置き換えてください
</Location>
```
2. Nginxの場合:
```
location /wp-admin {
allow 10.10.77.49; # あなたのIPアドレスに置き換えてください
deny all;
}
location ~* \wp-login.php {
allow 10.10.77.49; # あなたのIPアドレスに置き換えてください
deny all;
}
```
### 7.2. JSON REST API機能へのIPアクセスを制限するか、無効にする
WordPressは2つのREST機能(xmlrpc、json rest api)を提供しており、WordPressインストール時にデフォルトで有効になります。
REST APIはWordPressデータタイプのエンドポイントを提供し、投稿やデータのクエリ、リソースの変更、編集、削除などのタスクのためにサイトとのリモート操作を可能にします。
ほとんどのWordPressでは、REST API機能は必須ではありません。
これを有効にすると、WordPressがDDoS攻撃にさらされる可能性があり、リソース消費やサイトの速度低下を引き起こす可能性があります。
**監査:**
- JSON REST API機能が有効になっていることを確認します。(デフォルト: 有効)```
# curl -i -k https://yourwordpress.com/wp-json
(response)
HTTP/1.1 200 OK
cache-control: no-cache, no-store, must-revalidate, max-age=0
content-type: text/html; charset=UTF-8
...
Server: Apache
{"name":"mywordress","description":"".......................
対策:
「Disable REST API」プラグインのインストールと有効化:
JSON REST APIのIPアクセス制限:
<Location "/wp-json">
Require ip 10.10.77.49 # ご自身のIPアドレスに置き換えてください
</Location>
location ~ ^/wp-json/ {
allow 10.10.77.49; # 許可するIPアドレスに置き換えてください
deny all;
}
JSON REST APIと同様に、ほとんどのWordPressインストールでは不要なため、XML-RPC APIを無効にすることをお勧めします。
REST APIが必要な場合は、代わりにJSON REST APIを使用することを推奨します。
XML-RPCには2つの主な脆弱性があります:
ブルートフォース攻撃:
Pingbackを介したサービス拒否攻撃:
XML-RPCが有効な場合、このような攻撃に対して依然として悪用される可能性があります。
監査:
(response) HTTP/1.1 405 Method Not Allowed Date: Mon, 25 Jun 2018 08:30:24 GMT Server: Apache Allow: POST Content-Length: 42 Content-Type: text/plain; charset=UTF-8
XML-RPC server accepts POST requests only.
**対策:**
- プラグインを使用してXML-RPC機能を無効にする
**「Disable XML-RPC-API」プラグインをインストールして有効化:**
1. WordPress管理ダッシュボードに移動します。
2. プラグイン > 新規追加に移動します。
3. 「[Disable XML-RPC-API](https://wordpress.org/plugins/disable-xml-rpc-api/)」を検索してインストールし、有効化します。
4. XML-RPC-APIが無効になりました。
**XML-RPC pingback攻撃について:**
1. XML-RPCが有効であることを確認する
```
# curl -i -k https://yourwordpress.com/xmlrpc.php
(response)
HTTP/1.1 405 Method Not Allowed
Date: Mon, 25 Jun 2018 08:30:24 GMT
Server: Apache
Allow: POST
Content-Length: 42
Content-Type: text/plain; charset=UTF-8
XML-RPC server accepts POST requests only.
```
2. 利用可能なXML-RPCメソッドを検索する
```
(request)
POST /xmlrpc.php HTTP/1.1
Host: yourwordpress.com
Content-Length: 135
<?xml version="1.0" encoding="utf-8"?>
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
(response)
HTTP/1.1 200 OK
cache-control: no-cache, no-store, must-revalidate, max-age=0
...
Server: Apache
Content-Length: 4272
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><string>system.multicall</string></value>
<value><string>system.listMethods</string></value>
<value><string>system.getCapabilities</string></value>
<value><string>demo.addTwoNumbers</string></value>
<value><string>demo.sayHello</string></value>
<value><string>pingback.extensions.getPingbacks</string></value>
<value><string>pingback.ping</string></value>
<value><string>mt.publishPost</string></value>
...
<value><string>wp.getUsersBlogs</string></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
```
3. pingbackを実行する
- pingback攻撃の成功と具体的な確認方法は説明されていません。
```
(request)
POST /xmlrpc.php HTTP/1.1
Host: yourwordpress.com
Content-Length: 303
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>call-back url for pingback result</string></value>
</param>
<param>
<value><string>https://yourwordpress.com/</string></value>
</param>
</params>
</methodCall>
(response)
HTTP/1.1 200 OK
...
Server: Apache
Content-Length: 370
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>0</int></value>
</member>
<member>
<name>faultString</name>
<value><string></string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
```
### 7.4. WP-Cronを無効にする、または機能を制限する
WordPressでは、WP-Cron (wp-cron.php) は、投稿の予約公開、プラグイン・テーマの更新確認、通知メールの送信などのタスクを自動化するために使用されます。
WP-Cronは基本的に、ページが読み込まれるたびにスケジュールされたタスクのリストをチェックすることで機能します。
問題は、ページの読み込みが頻繁に行われる場合に発生します。
WP-Cronタスクはページ読み込みごとに実行されるため、複数回のアクセスが繰り返されると、それに応じてWP-Cronが呼び出されます。その結果、システムリソースが不足し、サイトが遅くなったり、停止したりする可能性があります。
これは実際に発生する問題であり、WordPressを標的とした脆弱性攻撃で頻繁に悪用されています。
WP-Cronが必要ない場合は、無効にすることをお勧めします。
必要な場合は、ローカルホストのみにアクセスを制限してください。
**監査:**
- WP-Cronが有効であることを確認します。(デフォルト: 有効)```
# curl -i -k https://yourwordpress.com/wp-cron.php
(response)
HTTP/1.1 200 ok
Date: Mon, 25 Jun 2018 08:30:24 GMT
Server: Apache
Allow: POST
Content-Length: 42
Content-Type: text/plain; charset=UTF-8
Remediation:
WP-Cron を無効にする手順:
/* That’s all, stop editing! Happy publishing. */define('DISABLE_WP_CRON', true);# Files Directive
<Files "wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Files>
# FilesMatch Directive
<FilesMatch "^wp-cron\.php$">
Require ip 127.0.0.1 # localhost only
</FilesMatch>
# Location Directive
<Location "/wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Location>
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
"ALTERNATE_WP_CRON" を有効にする手順:
/* That’s all, stop editing! Happy publishing. */define( 'ALTERNATE_WP_CRON', true );# Files Directive
<Files "wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Files>
# FilesMatch Directive
<FilesMatch "^wp-cron\.php$">
Require ip 127.0.0.1 # localhost only
</FilesMatch>
# Location Directive
<Location "/wp-cron.php">
Require ip 127.0.0.1 # localhost only
</Location>
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
システム Cron(crontab)を使用する例:
.. ... */10 * * * * curl http://yourwordpress.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
*/10 * * * * cd /var/www/yourwordpress.com/htdocs; php /var/www/yourwordpress.com/htdocs/wp-cron.php?doing_wp_cron > /dev/null 2>&1
*/10 * * * * cd /var/www/example.com/htdocs; wp cron event run --due-now > /dev/null 2>&1
**wp-cron.php を使用した DoS 攻撃の実行について:**
- wp-cron.php に大量のリクエストを送信する
- これによりスクリプトが過剰なリソースを消費し、最終的にサーバーに過負荷がかかる


## 8. セキュアな WordPress のためのシステム設定
WordPress の安全な運用を確保するには、Web サーバーの適切な設定とバックエンドコンポーネントの堅牢化が必要です。
以下に、確認および実装すべき重要な項目をいくつか示します。
### 8.1. サポート終了 (EOL) ではない WordPress および PHP バージョンの使用を確保する
安全な WordPress インストールを維持するには、サポート終了 (EOL) ではない WordPress および PHP のバージョンを使用することが不可欠です。
EOL バージョンはサポートが終了しており、セキュリティアップデートを受信できないため、ウェブサイトが未修正のセキュリティ問題に対して脆弱なままになります。
サポートされているバージョンを使用することで、発見された脆弱性が迅速に対処され、潜在的な攻撃からサイトを保護できます。
WordPress および PHP のバージョンを確認および更新するために必要な手順は次のとおりです。
**監査:**
- 現在の WordPress と PHP のバージョンが EOL ではないことを確認します。
**修復:**
- EOL ではないバージョンの WordPress と PHP をインストールして実行します。
- 2024年5月現在、サポートされている WordPress バージョンは 6.5 以上です。サポートされている PHP バージョンは 8.1、8.2、8.3 です。
- Web ホスティングサービスを利用している場合は、バージョン切り替え機能を活用して、WordPress と PHP の両方でサポートされているバージョンを実行していることを確認してください。
**2024年5月時点の EOL ステータス**
1. PHP: [supported-versions](https://www.php.net/supported-versions.php)
- 現在サポートされているバージョン: 8.1、8.2、8.3
2. WordPress: [current-releases](https://wordpress.org/download/releases/)
- 現在サポートされているバージョン: 6.5 シリーズ
**例: RockyLinux 8.5 での PHP**
- RockyLinux 8.5 では、デフォルトで利用可能な PHP バージョンは 7.2、7.3、7.4 です。
```
# dnf module list php
Rocky Linux 8 - AppStream
Name Stream Profiles Summary
php 7.2 [d] common [d], devel, minimal PHP scripting language
php 7.3 common [d], devel, minimal PHP scripting language
php 7.4 common [d], devel, minimal PHP scripting language
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
# dnf module enable php:7.4
==============================================================================================
Package Architecture Version Repository Size
==============================================================================================
Enabling module streams:
httpd 2.4
php 7.4
Transaction Summary
==============================================================================================
Is this ok [y/N]: y
Complete!
```
- PHP 7 はすでにサポート終了 (EOL) に達しています。PHP 8 へのアップグレードが推奨されます。
- PHP 8 は REMI リポジトリからインストールできます。
- REMI を使用して PHP 8.2 を有効化およびインストールする例を以下に示します。
```
# Rocky Linux 8 に PHP 8.2 をインストール
# dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
# dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
# dnf -y install yum-utils
# dnf module reset php
# dnf module install php:remi-8.2
Last metadata expiration check: 0:00:39 ago on Tue 13 Dec 2022 07:19:26 AM UTC.
Dependencies resolved.
=======================================================================================================================================
Package Architecture Version Repository Size
=======================================================================================================================================
Installing group/module packages:
php-cli x86_64 8.2.0-1.el8.remi remi-modular 5.4 M
php-common x86_64 8.2.0-1.el8.remi remi-modular 1.3 M
php-fpm x86_64 8.2.0-1.el8.remi remi-modular 1.9 M
php-mbstring x86_64 8.2.0-1.el8.remi remi-modular 574 k
php-xml x86_64 8.2.0-1.el8.remi remi-modular 254 k
Installing dependencies:
httpd-filesystem noarch 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 41 k
libxslt x86_64 1.1.32-6.el8 baseos 249 k
oniguruma5php x86_64 6.9.8-1.el8.remi remi-safe 212 k
Installing weak dependencies:
nginx-filesystem noarch 1:1.14.1-9.module+el8.4.0+542+81547229 appstream 23 k
Installing module profiles:
php/common
Enabling module streams:
httpd 2.4
nginx 1.14
php remi-8.2
Transaction Summary
=======================================================================================================================================
Install 9 Packages
# dnf update
# dnf install php
Last metadata expiration check: 0:00:23 ago on Tue 13 Dec 2022 07:29:55 AM UTC.
Dependencies resolved.
=======================================================================================================================================
Package Architecture Version Repository Size
=======================================================================================================================================
Installing:
php x86_64 8.2.0-1.el8.remi remi-modular 1.8 M
Installing dependencies:
apr x86_64 1.6.3-12.el8 appstream 128 k
apr-util x86_64 1.6.1-6.el8.1 appstream 104 k
httpd x86_64 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 1.4 M
httpd-tools x86_64 2.4.37-51.module+el8.7.0+1059+126e9251 appstream 108 k
libsodium x86_64 1.0.18-2.el8 epel 162 k
mailcap noarch 2.1.48-3.el8 baseos 38 k
mod_http2 x86_64 1.15.7-5.module+el8.6.0+823+f143cee1 appstream 153 k
rocky-logos-httpd noarch 86.3-1.el8 baseos 24 k
Installing weak dependencies:
apr-util-bdb x86_64 1.6.1-6.el8.1 appstream 23 k
apr-util-openssl x86_64 1.6.1-6.el8.1 appstream 26 k
php-opcache x86_64 8.2.0-1.el8.remi remi-modular 633 k
php-pdo x86_64 8.2.0-1.el8.remi remi-modular 166 k
php-sodium x86_64 8.2.0-1.el8.remi remi-modular 105 k
Transaction Summary
=======================================================================================================================================
Install 14 Packages
Total download size: 4.8 M
Installed size: 14 M
Is this ok [y/N]: y
# php -v
PHP 8.2.0 (cli) (built: Dec 6 2022 14:26:47) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies
```
**注意:**
- REMI リポジトリから PHP をインストールするための詳細な手順については、[rpms.remirepo.net](https://rpms.remirepo.net/) を参照してください。
- WordPress と PHP の互換性に関するドキュメント: [php-compatibility-and-wordpress-versions](https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/)
### 8.2. WordPress に必要な PHP 拡張機能のみが有効になっていることを確認する
WordPress サイトに必要な PHP 拡張機能のみが有効になっていることを確認してください。
不要な拡張機能はウェブサイトの攻撃対象領域を増やし、WordPress をセキュリティの脆弱性にさらす可能性があります。
必要な拡張機能のみを有効にすることで、潜在的なリスクを最小限に抑え、全体的なセキュリティを向上させることができます。
以下は、WordPress サイトが適切に機能するために必要なものです。**(セキュリティ強化目的のリストではありません)**
| 拡張機能 | 説明 |
|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| json | 他のサーバーとの通信や JSON 形式でのデータ処理に使用されます。 |
| mysqli | データベース操作のために MySQL に接続します。 |
| curl | リモートリクエスト操作を実行します。 |
| dom | テキストウィジェットのコンテンツの検証や IIS7+ の自動設定に使用されます。 |
| exif | 画像に保存されたメタデータを処理します。 |
| fileinfo | ファイルアップロードの MIME タイプを検出するために使用されます。 |
| hash | パスワードや更新パッケージを含むハッシュ化に使用されます。 |
| igbinary | 標準の PHP シリアライザーの代替としてパフォーマンスを向上させます。 |
| imagick | メディアアップロードにおいてより良い画質を提供します。詳細は WP_Image_Editor を参照してください。Ghost Script も利用可能な場合、よりスマートな画像リサイズ (小さい画像向け) と PDF サムネイルサポートを提供します。 |
| intl | 書式設定、文字変換、エンコーディング変換、カレンダー操作、準拠した照合、テキスト境界の特定、ロケール識別子、タイムゾーン、書記素の操作などを含むがこれらに限定されない、ロケール対応の操作を可能にします。 |
| mbstring | UTF8 テキストを適切に処理するために使用されます。 |
| openssl | 他のホストへの SSL ベースの接続。 |
| pcre | コード検索におけるパターンマッチングのパフォーマンスを向上させます。 |
| xml | サードパーティサイトなどからの XML 解析に使用されます。 |
| zip | プラグイン、テーマ、WordPress 更新パッケージの解凍に使用されます。 |
| bc | 任意精度の算術演算を提供し、2147483647 桁までの任意のサイズと精度の数値をサポートします。 |
| filter | ユーザー入力を安全にフィルタリングするために使用されます。 |
| image | Imagick がインストールされていない場合、GD グラフィックライブラリが画像操作のための機能制限付きの代替として使用されます。 |
| iconv | 文字セット間の変換に使用されます。 |
| shmop | Shmop は、PHP が Unix 共有メモリセグメントの読み取り、書き込み、作成、削除を可能にする、使いやすい関数のセットです。 |
| simplexml | XML 解析に使用されます。 |
| sodium | 署名の検証と安全なランダムバイトの提供を行います。 |
| xmlreader | XML 解析に使用されます。 |
| zlib | Gzip 圧縮と解凍。 |
必須の拡張機能はこちらにあります: [WordPress Hosting Handbook: PHP Extensions](https://make.wordpress.org/hosting/handbook/server-environment/#php-extensions)
**監査:**
- WordPress サイトに必要な PHP 拡張機能のみが有効になっていることを確認します。
**修復:**
- 不要な拡張機能を削除します。プラグインと一緒に拡張機能がインストールされることがあり、それらがサイトに不要な場合があります。
- 現在有効になっている PHP 拡張機能を確認するには、**php.ini** ファイルを確認するか、**phpinfo()** 関数を使用してすべてのアクティブな拡張機能を一覧表示できます。

- 特定の拡張機能は、必要でない場合は、潜在的なセキュリティ問題を防ぐために無効にする必要があります。
- 例えば、exif、fileinfo、imap、soap、pdo_sqlite、opcache などの拡張機能は、適切に使用されずに有効のままにしておくと悪用される可能性があります。
- Web ホスティングサービスを利用している場合、多くのプロバイダーは PHP 設定 (PHP 拡張機能の有効化や無効化を含む) を切り替えるための使いやすいインターフェースを提供しています。これらの機能を使用して、拡張機能を効果的に管理できます。
### 8.3. ファイルアップロード機能を備えたプラグインのセキュリティを確保する
ファイルアップロード機能を持つプラグインは、適切に保護されていない場合、重大なセキュリティリスクとなる可能性があります。ファイルアップロード機能の脆弱性により、攻撃者が Web シェルをアップロードし、システム全体を危険にさらす可能性があります。したがって、ファイルアップロード機能には検証およびサニタイズメカニズムが含まれていることが重要です。
なぜこれが重要か?
1. 拡張子の検証:
- サーバーは、許可されたタイプのホワイトリストに対してファイル拡張子を検証し、悪意のあるファイルのアップロードを防ぐ必要があります。
2. MIME タイプの確認:
- ファイルの MIME タイプをチェックして、期待されるタイプと一致することを確認し、セキュリティの層を追加する必要があります。
3. アップロードパスの制限:
- 検証なしでアップロードされたファイルへの直接アクセスを許可する公開パスが存在しないことを確認します。
ファイルアップロードの脆弱性は、攻撃者が実行可能コードをアップロードして任意のコマンドを実行するための直接的な経路を提供するため、特に危険です。ファイルアップロードの脆弱性は、SQL インジェクションなどの他のセキュリティ欠陥と比較して、特定および悪用が容易であることがよくあります。
**監査:**
- WordPress サイト上でファイルアップロード機能を持つプラグインを特定します。
- これらのプラグインが、アップロードされたファイルに対して拡張子や MIME タイプの検証を含む適切な検証チェックを実装していることを確認します。
**修復:**
- ファイルアップロード機能を持つプラグインに適切な検証がない場合は、そのセキュリティを強化するか、プラグインを削除します。
- 以下に、ファイルアップロード機能を持つ一般的な WordPress プラグインと、それらがファイル検証をどのように処理するかの例を示します。
**例: ファイルアップロード処理を行う一般的な WordPress プラグイン**
1. Contact Form 7
- Contact Form 7 は、WordPress で最も広く使用されているフォームプラグインの 1 つです。基本的なファイルアップロード機能と、拡張子および MIME タイプの検証を備えています。**許可された拡張子とMIMEタイプチェックのコード:**
```
function wpcf7_allowed_file_extensions() {
// Default allowed file extensions
$allowed_file_extensions = array(
'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx',
'xls', 'xlsx', 'txt', 'csv', 'rtf', 'html', 'zip'
);
return $allowed_file_extensions;
}
function wpcf7_handle_upload( $file ) {
$allowed_mime_types = wpcf7_allowed_file_extensions();
$file_type = wp_check_filetype( $file['name'] );
// Check if the file type is allowed
if ( ! in_array( $file_type['ext'], $allowed_mime_types ) ) {
return new WP_Error( 'wpcf7_upload_failed', __( 'File type is not allowed.', 'contact-form-7' ) );
}
// Handle the file upload
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
// Check if the upload was successful
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'wpcf7_upload_failed', $upload['error'] );
}
return $upload;
}
```
Contact Form 7では、`wpcf7_allowed_file_extensions()`関数が許可されたファイル拡張子のリストを返し、`wpcf7_handle_upload()`関数がアップロード前にファイル拡張子がこのリストに含まれているかをチェックします。
2. WPForms
- WPFormsは、許可されたファイルタイプをチェックすることでファイルアップロードを処理します。
**WPFormsのコード例:**
```
function wpforms_get_file_types() {
// Return an array of allowed file types
return array( 'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx' );
}
function wpforms_process_file_upload( $file ) {
$allowed_file_types = wpforms_get_file_types();
$file_type = wp_check_filetype( $file['name'] );
if ( ! in_array( $file_type['ext'], $allowed_file_types ) ) {
return new WP_Error( 'wpforms_upload_failed', __( 'File type is not allowed.', 'wpforms' ) );
}
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'wpforms_upload_failed', $upload['error'] );
}
return $upload;
}
```
3. WooCommerce
- WooCommerceも、アップロード処理コード内で許可されたファイル拡張子を直接定義しチェックします。
**WooCommerceのコード例:**
```
function woocommerce_handle_upload( $file ) {
$allowed_file_types = array( 'jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx' );
$file_type = wp_check_filetype( $file['name'] );
if ( ! in_array( $file_type['ext'], $allowed_file_types ) ) {
return new WP_Error( 'woocommerce_upload_failed', __( 'File type is not allowed.', 'woocommerce' ) );
}
$upload = wp_handle_upload( $file, array( 'test_form' => false ) );
if ( isset( $upload['error'] ) ) {
return new WP_Error( 'woocommerce_upload_failed', $upload['error'] );
}
return $upload;
}
```
**例: 悪意のあるファイルアップロードプラグイン**
- 悪意のあるプラグインは無害に見えるかもしれませんが、fileinfo拡張機能を悪用してセキュリティチェックを回避する可能性があります:
```
<?php
/*
Plugin Name: Simple Malicious Upload
Description: A plugin with hidden malicious file upload capability.
Version: 1.0
*/
function simple_file_upload_menu() {
add_menu_page('File Upload', 'File Upload', 'manage_options', 'file-upload', 'simple_file_upload_page');
}
add_action('admin_menu', 'simple_file_upload_menu');
function simple_file_upload_page() {
?>
<h1>File Upload</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="uploaded_file" />
<input type="submit" name="upload_file" value="Upload" />
</form>
<?php
if (isset($_POST['upload_file'])) {
simple_handle_file_upload();
}
}
function simple_handle_file_upload() {
if (!empty($_FILES['uploaded_file']['tmp_name'])) {
$file_tmp = $_FILES['uploaded_file']['tmp_name'];
$file_name = basename($_FILES['uploaded_file']['name']);
// Using fileinfo to check MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file_tmp);
finfo_close($finfo);
// Insecure handling: allows any PHP files to be uploaded
if ($mime_type === 'text/plain' || $mime_type === 'application/x-php') {
$upload_dir = wp_upload_dir();
$upload_file = $upload_dir['path'] . '/' . $file_name;
// Move the uploaded file to the uploads directory
if (move_uploaded_file($file_tmp, $upload_file)) {
echo "File uploaded successfully.";
} else {
echo "File upload failed.";
}
} else {
echo "Invalid file type.";
}
}
}
?>
```
**悪用の説明:**
- この悪意のあるプラグインは、MIMEタイプが`application/x-php.`の場合にPHPファイルのアップロードを許可します。
- 攻撃者はこの機能を利用してPHPウェブシェルをアップロードできます。
- アップロード後、攻撃者はファイルのURLにアクセスし任意のコマンドを実行します。
**例: PHPウェブシェルコード**```
<?php
if (isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
}
?>
攻撃の実演
http://yourwordpress.com/wp-content/uploads/webshell.php でWebシェルにアクセスします。http://yourwordpress.com/wp-content/uploads/webshell.php?cmd=ls にアクセスすることで、攻撃者は任意のコマンドを実行できます。注記:
PHP関数と設定が適切に構成されていることを確認することで、WordPressサイトのセキュリティを大幅に向上させることができます。設定が適切でない場合、リモートコード実行、情報漏洩、セッションハイジャックなど、さまざまな脆弱性にさらされる可能性があります。これらの関数を無効化または適切に設定することでPHPを強化することが重要です。
なぜこれが重要なのか?
リモートコード実行:
allow_url_fopen のような設定や exec のような関数はリモートコード実行を可能にし、システムが侵害される可能性があります。情報漏洩:
display_errors や expose_php のようなオプションはサーバー設定に関する機密情報を漏洩させ、攻撃者が脆弱性を見つけやすくします。セッションセキュリティ:
session.cookie_secure や session.cookie_httponly のような適切なセッション管理設定は、セッションクッキーがクライアントサイドスクリプトを介してアクセスされたり、安全でないチャネルで送信されたりするのを防ぎます。監査:
修復:
allow_url_fopen:
file_get_contents(), fopen(), include(), require() などの関数がFTPまたはHTTP経由でリモートロケーションからデータを取得できるようになります。WordPressおよび多くのWordPressプラグインは、さまざまな機能のために allow_url_fopen を必要とする場合があります。ただし、この設定を常に有効にしておく必要はありません。セキュリティ上の理由から、必要なときだけ有効にする方が良いでしょう。
; (Optional) Disable allow_url_fopen, if not unnecessary
allow_url_fopen = Off
display_errors:
; Disable PHP errors not be displayed on your WordPress website
display_errors = Off
expose_php:
; Prevent exposing PHP version in HTTP response headers
expose_php = Off
session.cookie_secure
session.cookie_secure:
; Ensure session cookies are sent over HTTPS
session.cookie_secure = On
session.cookie_httponly
session.cookie_httponly:
; Make session cookies inaccessible to JavaScript
session.cookie_httponly = On
例:以下は実際のWordPressで無効化されたPHP関数のリストです``` system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
### 8.5. Webサーバーを非rootユーザーとして実行する - サーバーアプリケーション用の一意かつ非特権のユーザーとグループ
多くの場合、Webサーバーは「www-data」(Debian/Ubuntu)や「apache」(RHEL/CentOS)などのユーザーとして実行されます。
これらのユーザーは、サーバー上で特別な権限を持たない専用のサービスアカウントであり、Webサーバーのワーカープロセスが引き継ぐユーザーとグループを指定するために使用されます。
これらのユーザーがシステム権限を持っている場合、またはrootとして実行されている場合は、変更する必要があります。
**監査:**
- Webサーバープロセスを実行しているユーザーを確認します。(具体的には、Webサーバーのワーカープロセスです。)
1. Apacheの場合:
```
# ps -ef | grep httpd
root 2257 1 0 Apr08 ? 00:00:01 /usr/local/apache/bin/httpd -k start
apache 5678 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5679 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5680 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
apache 5681 1234 0 Apr08 ? 00:00:00 /usr/sbin/httpd -k start
```
2. Nginxの場合:
```
# ps -ef | grep nginx
root 626653 1 0 Apr08 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 626654 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626655 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626656 626653 0 Apr08 ? 00:00:00 nginx: worker process
nginx 626657 626653 0 Apr08 ? 00:00:00 nginx: worker process
```
**修正措置:**
- Webサーバーは、非特権の専用アカウントとして実行する必要があります。
- 多くの場合、「www-data」、「apache」、「nginx」、「nobody」、「daemon」などの一般的に使用されるアカウントのいずれかが利用されます。
1. Apacheの場合:
```
# vim /etc/httpd/httpd.conf
..
...
User www-data
Group www-data
..
...
```
2. Nginxの場合:
```
# vim /etc/nginx/nginx.conf
..
...
user daemon;
```
**注記:**
- Webサーバーのプロセスユーザーは、シェルログイン権限を持つべきではありません。 ```
# cat /etc/passwd | grep -i www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
WordPressはPHPで構築されているため、PHPコードを適切に実行するには正しいシステム設定が必要です。
WordPressでのPHPコードの実行は、FastCGIプロセスマネージャーであるPHP-FPMによって管理されます。
PHP-FPMの安全な運用を確保するために、権限のない専用のサービスアカウントで実行する必要があります。
通常、WebサーバープロセスアカウントとPHP-FPMアカウントは同じアカウントに設定されます。ただし、セキュリティを強化するには、それらを別々のアカウントで実行する方がよいでしょう。
その理由は次の2つです:
プロセスの分離:
最小権限の原則:
監査:
root 1234 1 0 12:00 ? 00:00:01 php-fpm: master process (/etc/php-fpm.conf) php-fpm 5678 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5679 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5680 1234 0 12:00 ? 00:00:00 php-fpm: pool www php-fpm 5681 1234 0 12:00 ? 00:00:00 php-fpm: pool www
**修復方法:**
- PHP-FPMは、非特権の専用アカウントで実行する必要があります。
- ほとんどの場合、使用されるアカウントは'php-fpm'です。
**PHP-FPMのプロセスアカウントの変更:**```
# vim /etc/php-fpm.d/www.conf # Adjust the path based on your PHP version
...
user = php-fpm
group = php-fpm
listen.owner = php-fpm
listen.group = php-fpm
PHP-FPMプロセスアカウントにはシェルログイン権限を与えるべきではありません。```
php-fpm❌999:999:PHP-FPM:/run/php:/usr/sbin/nologin
**注記:**
- PHP-FPM プロセスとウェブサーバープロセスに異なるユーザーアカウントを使用することは、セキュリティの観点から望ましいです。
- セキュリティ向上のためにどちらが良いかと問われた場合、それらは異なるべきです。この文脈では同じ実行アカウントを使用しないでください。
### 8.7. WordPressホームディレクトリの安全な設定の確保
ウェブサーバーを安全に運用するには、WordPressホームディレクトリの所有者とパーミッションを適切に設定することが重要です。
ほとんどの場合、WordPressのファイルとディレクトリの所有者とパーミッションは、ウェブサーバーのプロセスアカウントに一致するように設定されます。
この設定により、ウェブサーバーはwebroot内のファイルにアクセスでき、エラーなく動作します。
しかし、この設定は安全ではありません。
例えば、ウェブサーバープロセスが 'apache' であり、webrootディレクトリとファイルの両方が 'apache' によって所有されている場合、深刻な脆弱性につながる可能性があります。
攻撃者はこれらの脆弱性を悪用して、WordPressホームディレクトリ内の重要なファイルやディレクトリへの不正アクセスを取得する可能性があります。
**一般的な脆弱性の例:**
- ウェブサーバーのプロセスアカウントとホームディレクトリ(webroot)およびファイルの両方が 'apache' によって所有されている場合:
- ウェブサイトの脆弱性やシステムへの外部アクセス(webshellなど)が発生した場合、攻撃者はwebroot内で以下のようなさまざまな操作を実行できます:
1. webroot内のファイルやディレクトリの作成、変更、削除。
2. ウェブアクセスログの改ざん(変更、削除、作成を含む。一部の環境を除く)。
3. ログインユーザーのアクティブなセッションクッキーへのアクセスを取得する可能性(特に脆弱な環境において)。
これらのリスクを軽減するには、WordPressホームディレクトリの所有者とパーミッションを適切に調整することが重要です。
**修正方法:**
- ホームディレクトリ(webroot)とファイルの所有者を 'root:root' に設定します。(ウェブサーバーのプロセスアカウントと同じに設定しないでください。)
- ディレクトリとファイルのデフォルトのUMASKは022です。(ディレクトリ:755、ファイル:644)
- ウェブサービスによるファイルアップロードなど、書き込みアクセスが必要なディレクトリについては、それらのディレクトリの所有者をウェブサーバーのプロセスアカウントに設定します。
**WordPressで一般的に書き込み権限が必要なディレクトリ:**```
/wp-content/uploads
/wp-content/cache
/wp-content/wflogs (when using security plugins like Wordfence)
/wp-content/upgrade (used during the WordPress upgrade process)
上記の修復措置に従ってホームディレクトリの所有者とパーミッションを設定した後、 WordPressホームディレクトリの出力は次のとおりです。
例: WordPressホームディレクトリ``` drwxr-xr-x 5 root root 4096 May 27 2024 . drwxr-xr-x 3 root root 4096 May 27 2024 .. -rw-r--r-- 1 root root 418 May 27 2024 index.php -rw-r--r-- 1 root root 19935 May 27 2024 license.txt -rw-r--r-- 1 root root 7346 May 27 2024 readme.html -rw-r--r-- 1 root root 7106 May 27 2024 wp-activate.php drwxr-xr-x 9 root root 4096 May 27 2024 wp-admin -rw-r--r-- 1 root root 351 May 27 2024 wp-blog-header.php -rw-r--r-- 1 root root 2328 May 27 2024 wp-comments-post.php -rw-r--r-- 1 root root 4973 May 27 2024 wp-config-sample.php -rw-r--r-- 1 root root 2755 May 27 2024 wp-config.php drwxr-xr-x 8 root root 4096 May 27 2024 wp-content -rw-r--r-- 1 root root 3940 May 27 2024 wp-cron.php drwxr-xr-x 25 root root 12288 May 27 2024 wp-includes -rw-r--r-- 1 root root 2496 May 27 2024 wp-links-opml.php -rw-r--r-- 1 root root 3300 May 27 2024 wp-load.php -rw-r--r-- 1 root root 51556 May 27 2024 wp-login.php -rw-r--r-- 1 root root 8403 May 27 2024 wp-mail.php -rw-r--r-- 1 root root 24568 May 27 2024 wp-settings.php -rw-r--r-- 1 root root 30869 May 27 2024 wp-signup.php -rw-r--r-- 1 root root 4620 May 27 2024 wp-trackback.php -rw-r--r-- 1 root root 3065 May 27 2024 xmlrpc.php
**In case php-fpm and web server process accounts are different (Separate Permissions)**
If the web server process account is "apache" and the php-fpm process account is "php-fpm".
Change the permissions of the directories that require write access in WordPress (e.g., /wp-content/uploads).
- Owner: php-fpm
- Group: apache
- Directory Permissions: 775 (755 if necessary)
**File and Directory Structure**
Set the write permissions for the necessary directories so that both "php-fpm" and "apache" accounts can write.```
ex) /service/wordpress/www
├── index.php (root:root, 644)
├── license.txt (root:root, 644)
├── readme.html (root:root, 644)
├── wp-activate.php (root:root, 644)
├── wp-admin/ (root:root, 755)
├── wp-blog-header.php (root:root, 644)
├── wp-comments-post.php (root:root, 644)
├── wp-config-sample.php (root:root, 644)
├── wp-config.php (root:root, 644)
├── wp-content/ (root:root, 755)
│ ├── plugins/ (root:root, 755)
│ ├── themes/ (root:root, 755)
│ ├── uploads/ (php-fpm:apache, 775)
│ │ ├── 2024/ (php-fpm:apache, 775)
│ │ └── ... (php-fpm:apache, 775)
│ └── ... (root:root, 755)
├── wp-cron.php (root:root, 644)
├── wp-includes/ (root:root, 755)
├── wp-links-opml.php (root:root, 644)
├── wp-load.php (root:root, 644)
├── wp-login.php (root:root, 644)
├── wp-mail.php (root:root, 644)
├── wp-settings.php (root:root, 644)
├── wp-signup.php (root:root, 644)
├── wp-trackback.php (root:root, 644)
└── xmlrpc.php (root:root, 644)
概要
このように設定することで、WebサーバーとPHP-FPMの権限を分離し、ホームディレクトリの所有権とパーミッション設定を正しく適用して、セキュリティを強化できます。
この方法はWordPressだけでなく、Webコンテンツを提供するあらゆるWebサーバー構成にも適用できます。
ファイルをアップロードできるディレクトリでPHPの実行が無効になっていることを確認することは、安全な環境を維持するために重要です。
書き込み権限があるアップロードディレクトリは、攻撃者がWebシェルなどの悪意のあるスクリプトをアップロードし、実行してサーバーを侵害する可能性がある標的となります。
なぜ重要か?
Webシェル攻撃の軽減:
攻撃対象領域の削減:
セキュリティのベストプラクティスへの準拠:
監査:
修復方法:
/wp-content/uploadsディレクトリなどの書き込み権限があるディレクトリでPHPの実行を無効にします。設定手順
<Location "/wp-content/uploads">
SetHandler application/octet-stream
</Location>
location /wp-content/uploads {
default_type application/octet-stream;
}
<Location "/wp-content/uploads">
php_flag engine off
# または代替
php_value engine 0
</Location>
<Location "/wp-content/uploads">
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Location>
<Directory "/var/www/html/yourwordpress/wp-content/uploads">
# PHP実行を無効化
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Directory>
location /wp-content/uploads {
location ~ \.php$ {
fastcgi_pass off;
}
}
location /wp-content/uploads {
location ~ \.php$ {
deny all;
}
}
これらの設定により、たとえPHPファイルが/wp-content/uploadsディレクトリにアップロードされても実行できなくなり、潜在的な攻撃を防ぐことができます。
設定ディレクティブの説明
SetHandler application/octet-stream:
php_flag engine off / php_value engine 0:
SetHandler none:
注記:
/wp-content/uploads ディレクトリ内の画像ファイルは、`` タグを使用して引き続きアクセス可能で正しく表示されます。```
これらの設定を適用することで、アップロードディレクトリを潜在的なスクリプト実行の脆弱性から大幅に強化できます。
### 8.9. Webサーバーがドメインベースのホストヘッダーにのみ応答するようにする
Webサーバーを保護するには、サーバーがドメイン名へのリクエストにのみ応答し、サーバーのIPアドレスへの直接リクエストには応答しないようにすることが不可欠です。
これは、VirtualHostディレクティブを適切に設定することで実現できます。
ほとんどの場合、Webサービスは `https://yourwordpress.com` のようなドメイン名を介してアクセスされます。Webサーバーはこのリクエストを受信し、適切なコンテンツを提供します。この動作を強制するには、正しいHostヘッダーを持つリクエストにのみ応答するようにWebサーバーを設定する必要があります。
**IPベースのアクセスを許可する潜在的なセキュリティリスク**
1. サービスの列挙:
- 攻撃者はIPアドレスを使用してサーバー上で実行中のサービスを列挙し、脆弱性を発見して悪用するリスクが高まります。
2. 機密情報の露出:
- 設定が不適切なサーバーは、IP経由でアクセスされた場合に公開すべきでないディレクトリやファイル、その他の機密情報を公開する可能性があります。
3. セキュリティ制御の迂回:
- IPベースのアクセスは、ドメインベースのアクセスに対してのみ適用されるセキュリティ対策を迂回し、不正アクセスにつながる可能性があります。
**監査:**
- Webサーバーがドメインベースのリクエストにのみ応答し、直接のIPアドレスアクセスには応答しないように設定されていることを確認してください。
**是正措置:**
- Webサーバーが指定されたドメインに基づいてのみリクエストを処理し、その他のリクエストを適切に拒否またはリダイレクトするように設定します。
**設定手順**
1. デフォルトのVirtualHost設定
- 指定されていないすべてのリクエストをキャッチし、403 Forbiddenを返すか、リダイレクトするデフォルトのVirtualHostを作成します。
**Apacheの場合:**
```
<VirtualHost _default_:80>
DocumentRoot /var/www/html/yourwordpress
...
<Location />
Require all denied
</Location>
<VirtualHost _default_:443>
DocumentRoot /var/www/html/yourwordpress
...
SSLEngine on
SSLCertificateFile /path/to/ssl/certificate.crt;
SSLCertificateKeyFile /path/to/ssl/private.key;
...
<Location />
Require all denied
</Location>
</VirtualHost>
```
**Nginxの場合:**
```
server {
listen 80 default_server;
return 403;
}
server {
listen 443 ssl default_server;
...
ssl_certificate /path/to/ssl/certificate.crt;
ssl_certificate_key /path/to/ssl/private.key;
...
return 403;
}
```
2. ドメインベースのVirtualHost設定
- ドメイン用にVirtualHostが設定されていることを確認してください。
**Apacheの場合:**
```
<VirtualHost *:80>
ServerName yourwordpress.com
...
Redirect permanent / https://yourwordpress.com/
</VirtualHost>
<VirtualHost *:443>
ServerName yourwordpress.com
DocumentRoot /var/www/html/yourwordpress
...
SSLEngine on
SSLCertificateFile /etc/httpd/to/ssl/certificate.crt;
SSLCertificateKeyFile /etc/httpd/to/ssl/private.key;
...
</VirtualHost>
```
**Nginxの場合:**
```
server {
listen 443 ssl;
server_name yourwordpress.com;
root /var/www/html/wordpress;
...
ssl_certificate /path/to/ssl/certificate.crt;
ssl_certificate_key /path/to/ssl/private.key;
...
```
3. テスト
- 以下は、`yourwordpress.com` のデフォルトVirtualHostとドメインベースVirtualHostの作成例です。
- `yourwordpress.com` のデフォルトVirtualHostとドメインベースVirtualHostを作成した後、ドメインベースではないリクエスト(https://ip)に対してはアクセスが拒否され(403エラー)、403エラー画面が表示されます。
```
$ curl -i -k http(s)://10.10.66.88
HTTP/1.1 403 Forbidden
Server: nginx
Date: Mon, 03 Jun 2024 23:23:13 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
$ curl -i -k https://yourwordpress.com
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 03 Jun 2024 23:32:12 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9
Connection: keep-alive
Hello, yourwordpress.com
```
- サーバー間通信や同一IPサブネット内での通信が必要な場合は、特定のIPアドレスからのアクセスを許可するようにデフォルトVirtualHostを設定できます。
これらの設定を実装することで、Webサーバーはドメインに向けられたリクエストにのみ応答するようになります。
### 8.10. 完成したWebサーバー設定
以下は、セキュリティガイドラインを含むWebサーバー設定の完成例です。WordPressのWebサーバー環境に応じて調整して使用してください。
1. Apache
```
<VirtualHost _default_:80>
DocumentRoot /var/www/html/yourwordpress
ErrorLog /var/log/httpd/http.ip.error.log
CustomLog /var/log/httpd/http.ip.access.log combined
<Location />
Require all denied
</Location>
<VirtualHost _default_:443>
DocumentRoot /var/www/html/current/public
ErrorLog /var/log/httpd/https.ip.error.log
CustomLog /var/log/httpd/https.ip.access.log combined
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.crt
SSLCertificateKeyFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.key
SSLSessionTimeout 1d
SSLSessionCache shared:MozSSL:10m
SSLSessionTickets off
SSLProtocol TLSv1.2 TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
SSLHonorCipherOrder off
<Location />
Require all denied
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName yourwordpress.com
Redirect permanent / https://yourwordpress.com/
</VirtualHost>
<VirtualHost *:443>
ServerName yourwordpress.com
Protocols h2 http/1.1
DocumentRoot /var/www/html/current/public
ErrorLog /var/log/httpd/https.yourwordpress.com.error.log
CustomLog /var/log/httpd/https.yourwordpress.com.access.log combined
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.crt
SSLCertificateKeyFile /etc/httpd/conf.d/cert/yourwordpress.com_ssl.key
SSLSessionTimeout 1d
SSLSessionCache shared:MozSSL:10m
SSLSessionTickets off
SSLProtocol TLSv1.2 TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
SSLHonorCipherOrder off
<Directory /var/www/html/current/public>
Options -Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Deny PHP execution in uploads directory
<Directory "/var/www/html/current/public/wp-content/uploads">
<FilesMatch "\.php$">
SetHandler none
Require all denied
</FilesMatch>
</Directory>
# PHP Serving
ProxyPassMatch ^/(?!wp-content/uploads/.*\.php$)(.*\.php(/.*)?)$ unix:/var/run/php-fpm/php-fpm.sock|fcgi://localhost/var/www/html/current/public
#ProxyPassMatch ^/(?!wp-content/uploads/.*\.php$)(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/current/public
# Favicon
<Location "/favicon.ico">
ErrorDocument 404 "Not Found"
SetEnvIf Request_URI "^/favicon\.ico$" no_log
</Location>
# Robots.txt
<Location "/robots.txt">
Require all granted
SetEnvIf Request_URI "^/robots\.txt$" no_log
</Location>
# Restrict access to wp-cron.php
<Files "wp-cron.php">
Require all denied
Require ip 127.0.0.1
</Files>
# Restrict access to wp-json
<Location "/wp-json/">
Require all denied
Require ip 127.0.0.1
Require ip 10.10.77.49
Require ip 10.10.71.20
</Location>
# Restrict access to wp-admin
<Location "/wp-admin">
Require all denied
Require ip 10.10.77.49
Require ip 10.10.71.20
</Location>
<Files "wp-login.php">
Require all denied
Require ip 10.10.77.49
Require ip 10.10.71.20
</Files>
# Deny access to hidden files
<FilesMatch "^\.">
Require all denied
</FilesMatch>
</VirtualHost>
```
2. Nginx
```
server {
listen 80 default_server;
listen 443 default_server ssl http2;
error_log /var/log/nginx/http.ip.error.log;
access_log /var/log/nginx/http.ip.access.log main;
ssl_certificate /etc/nginx/conf.d/cert/yourwordpress.com_ssl.crt;
ssl_certificate_key /etc/nginx/conf.d/cert/yourwordpress.com_ssl.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
location / {
deny all;
}
}
server {
listen 443 ssl http2;
server_name yourwordpress.com;
root /var/www/html/wordpress;
error_log /var/log/nginx/https.yourwordpress.com.error.log;
access_log /var/log/nginx/https.yourwordpress.com.access.log main;
ssl_certificate /etc/nginx/conf.d/cert/yourwordpress.com_ssl.crt;
ssl_certificate_key /etc/nginx/conf.d/cert/yourwordpress.com_ssl.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Restrict to access Wordpress Cron
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
access_log off;
log_not_found off;
}
# Restrict to access json rest-api
location ~ ^/wp-json/ {
allow 127.0.0.1; # Allow localhost
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
access_log off;
log_not_found off;
}
# Restrict to access Wordpress Admin
location = /wp-admin {
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
}
location ~* \wp-login.php {
allow 10.10.77.49; # Allow myip
allow 10.10.71.20; # Allow myip
deny all;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
location /wp-content/uploads {
location ~ \.php$ {
deny all;
}
}
# Other example
# location ~* /(?:uploads|files)/.*\.php$ {
# deny all;
# }
# Rewrite rules, sends everything through index.php and keeps the appended query string intact
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Serving PHP
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\\.php)(/.+)$;
# fastcgi_pass 127.0.0.1:9000; # With php-cgi (or other tcp sockets):
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # With php-fpm (or other unix sockets):
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
```
## 9. WordPressのセキュリティアップデートを確実に行う
WordPressは、脆弱性が発見された場合に新しいバージョンのアップデートをリリースすることでセキュリティ脆弱性に対処しています。
例えば、WordPress 6.5.2でセキュリティ脆弱性が見つかった場合、バージョン6.5.3で対処され配布されます。
セキュリティアップデートはバージョンごとに管理されていないため、セキュリティ脆弱性に対処するには定期的なバージョンアップデートが必要です。
アップデートに関する公式情報は、WordPressのリリース情報を参照してください:
[WordPress Releases](https://wordpress.org/download/releases/)
**是正措置:**
- WordPressを定期的に更新してください。
- WordPressはバージョンごとにアップデート(セキュリティアップデートを含む)を管理していません。
- 2024年5月20日時点では、バージョン6.5のみがメンテナンス対象です。
**注意:**
- ベータ版、Nightlyビルド、その他のSubversionチェックアウトはサポートされていません。
- フォークされた製品や、公式のWordPressリリースではないバージョンの使用は避けてください。
- サポートされているバージョンのドキュメント: [Supported Versions](https://wordpress.org/documentation/article/supported-versions/)
## 10. WordPressの定期的なセキュリティ脆弱性チェックを確実に行う
WordPressはコンテンツ管理システム(CMS)ソフトウェアです。
パッケージ化されたソフトウェアであるため、セキュリティ脆弱性は主にそのコンポーネント(コアファイル、プラグイン、テーマなど)で発生します。
特定の要件に合わせてカスタマイズされたWebアプリケーションとは異なり、WordPressに適した方法でセキュリティ脆弱性の特定と対処を行う必要があります。
WordPressで構築されたウェブサイトが大幅にカスタマイズされておらず、WordPressの性質を保持している場合、WPScanを使用してセキュリティ脆弱性を簡単にチェックできます。
WPScanは一部有料のソフトウェアですが、基本の無料ティアには機能制限はありません。WordPressのセキュリティ脆弱性の定期的なチェックと対応が可能です。
**是正措置:**
- WPScan(またはWordPressをスキャンできる類似ツール)を使用して定期的に脆弱性チェックを実施してください。
- 脆弱性が見つかった場合は、確認し、それを排除するために必要なアクションを実行してください。ほとんどの場合、アップデートによって解決されます。
- [WPScanユーザードキュメント](https://github.com/wpscanteam/wpscan/wiki/WPScan-User-Documentation)を参照してください。
- WordPressでよく見られる一般的な脆弱性の詳細情報: [Extending WordPress Common Security Vulnerabilities](https://learn.wordpress.org/tutorial/extending-wordpress-common-security-vulnerabilities/)
**WPScan:**```
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.22
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[+] URL: https://yourwordpress.com/ [192.168.10.100]
[+] Started: Fri May 24 14:39:06 2024
Interesting Finding(s):
[+] Headers
..
...
| - content-security-policy: upgrade-insecure-requests
| Found By: Headers (Passive Detection)
| Confidence: 100%
..
...
[+] XML-RPC seems to be enabled: https://yourwordpress.com/xmlrpc.php
| Found By: Link Tag (Passive Detection)
| Confidence: 30%
| References:
| - http://codex.wordpress.org/XML-RPC_Pingback_API
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner/
| - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos/
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login/
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access/
..
...
[+] Finished: Fri May 24 14:39:48 2024
[+] Requests Done: 187
[+] Cached Requests: 7
[+] Data Sent: 56.32 KB
[+] Data Received: 605.595 KB
[+] Memory used: 276.602 MB
[+] Elapsed time: 00:00:42
| No | ロール | 説明 | 管理スタッフ |
|---|
| 1 | 管理者 | すべてのWordPress機能へのフルアクセスを持ち、サイト上のすべてのコンテンツを管理できます。 | システム管理者 |
| 2 | 編集者 | 他のユーザーの投稿を管理・公開でき、コンテンツの編集や公開ができます。 | 運用サービス管理者、内部コンテンツ投稿者 |
| 3 | 投稿者 | 自分の投稿を作成・公開でき、自分の投稿を編集する権限があります。 | 内部コンテンツ投稿者 |
| 4 | 寄稿者 | コンテンツを作成できますが、公開はできません。投稿は管理者によってレビューされ公開されます。 | 内部コンテンツ投稿者 |
| 5 | 購読者 | サイトにログインして自分のプロファイルを管理できますが、コンテンツの作成や編集はできません。 | 内部コンテンツ投稿者 |
open_basedir:
; Restrict PHP file access to the specified directory
open_basedir = "/path/to/your/web/root"
例:
open_basedir = "/var/www/html:/tmp"
This configuration allows PHP to access files only within the /var/www/html directory and the temporary directory /tmp.
disable_functions:
; Disable potentially dangerous PHP functions
disable_functions = "system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail"
無効化された関数の説明:
system, exec, shell_exec, passthru:
mysql_list_dbs:
ini_alter:
dl:
symlink, link:
chgrp:
leak:
popen:
apache_child_terminate:
virtual:
mb_send_mail: