2026年10月1日
2026年10月1日
OWASP Top 10:2025で見直すWordPressのセキュリティ対策|運用と開発のチェックリスト
OWASP(Open Worldwide Application Security Project)は、Web アプリケーションのセキュリティを扱う非営利の団体です。代表的な成果物の OWASP Top 10 は、Web アプリケーションで多く見られる重大なリスクを10の分類にまとめたもので、2026年10月時点の最新版は OWASP Top 10:2025 です。
OWASP Top 10 は WordPress 専用の基準ではありませんが、分類ごとに「WordPress では何を確認するか」を当てはめると、対策の抜けを見つけやすくなります。この記事では、サイトを運用する人が確認する設定と、テーマやプラグインを書く人が守る書き方を、分類ごとに整理します。
OWASP Top 10:2025 の一覧と WordPress での主な対策
| 分類 | 内容 | WordPress での主な対策 |
|---|---|---|
| A01 アクセス制御の不備 | 権限のない人が操作・閲覧できてしまう | 権限グループの見直し、current_user_can()・nonce・permission_callback |
| A02 セキュリティ設定のミス | 既定のまま・不要な機能が有効 | DISALLOW_FILE_EDIT、デバッグ表示の停止、ファイルの権限 |
| A03 ソフトウェアサプライチェーンの不備 | 依存するソフトの脆弱性・改ざん | プラグイン・テーマの選定と更新、使わないものの削除 |
| A04 暗号化の失敗 | 通信や秘密情報が保護されていない | HTTPS、FORCE_SSL_ADMIN、認証用キーの管理 |
| A05 インジェクション | SQL インジェクション・XSS など | $wpdb->prepare()、エスケープ関数、入力の無害化 |
| A06 安全でない設計 | 設計段階で安全が考慮されていない | 最小権限、公開範囲の設計 |
| A07 認証の失敗 | 推測しやすいパスワード、総当たり攻撃 | 強いパスワード、2段階認証、ログイン試行の制限 |
| A08 ソフトウェアやデータの整合性の不備 | 改ざんされたファイルやデータを信用してしまう | チェックサムの確認、入手元の限定 |
| A09 ログと警告の不備 | 攻撃や異常に気付けない | 操作ログ、サーバーログ、更新・エラーの通知 |
| A10 例外的な状況の不適切な扱い | エラー時に情報が漏れる・安全でない状態になる | エラー表示の停止、is_wp_error() の確認 |
分類名の日本語は、英語の分類名(A01:2025 - Broken Access Control など)をもとにこの記事で訳したもので、OWASP の日本語版の表記とは異なる場合があります。
作業前の準備: バックアップ
設定を変える前に、ファイルとデータベースのバックアップを取ります。WP-CLI が使える場合は次のとおりです。
mkdir -p ~/backup
cd /var/www/html/wordpress
wp db export ~/backup/db_$(date +%Y%m%d).sql
tar czf ~/backup/files_$(date +%Y%m%d).tar.gz -C /var/www/html wordpress
バックアップは Web から見える場所(公開ディレクトリーの中)に置かないでください。定期的な取得と保存先の考え方は WordPressのバックアップの基本 を参考にしてください。
A01 アクセス制御の不備
運用での確認
- 「ユーザー」→「ユーザー一覧」で、退職者や使っていないアカウント、必要以上に「管理者」になっているアカウントがないか確認します。
- 記事を書くだけの人は「投稿者」や「編集者」など、必要な権限グループにします。
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
開発での確認
- 管理画面の処理や保存処理では、
current_user_can()で権限を確かめ、nonce(wp_nonce_field()とcheck_admin_referer()、Ajax ならcheck_ajax_referer())で本人の操作か確かめます。 - REST API のルートには
permission_callbackを書きます。WordPress 5.5 以降、省略すると開発者向けの注意が出ます。誰でも使ってよいルートだけ__return_trueにします。
<?php
add_action( 'rest_api_init', function () {
register_rest_route(
'myplugin/v1',
'/settings',
array(
'methods' => 'POST',
'callback' => 'myplugin_save_settings',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
)
);
} );
A02 セキュリティ設定のミス
公式ドキュメントの「WordPress の安全対策(Hardening WordPress)」に沿って、次を確認します。
// wp-config.php(「編集が必要なのはここまでです」の行より上)
define( 'DISALLOW_FILE_EDIT', true ); // 管理画面のテーマ・プラグインのファイル編集を無効にする
define( 'WP_DEBUG', false ); // 本番ではデバッグを無効にする
DISALLOW_FILE_EDITは、管理画面のファイル編集機能を止めます。公式ドキュメントでは、悪意のあるファイルのアップロードまでは防げないが、一部の攻撃は止められると説明されています。- ファイルの権限は、公式ドキュメントではディレクトリーが 755、ファイルが 644、
wp-config.phpは 400 か 440(自分と Web サーバーだけが読める)とされています。詳しくは WordPressのファイルのパーミッション設定 を参考にしてください。 - Web サーバーのディレクトリー一覧表示を止めます(Apache なら
Options -Indexes)。 - 使っていない機能を閉じます。XML-RPC を使っていなければ XML-RPCの無効化 を検討します。
- セキュリティ関連の HTTP ヘッダーは セキュリティヘッダーの設定 を参考にしてください。
A03 ソフトウェアサプライチェーンの不備
WordPress サイトの脆弱性の多くは、本体よりもプラグインやテーマから見つかります。
# 更新があるものを一覧する
wp core check-update
wp plugin list --update=available
wp theme list --update=available
# 無効のまま置いてあるプラグイン・テーマを一覧する
wp plugin list --status=inactive
wp theme list --status=inactive
- 使っていないプラグイン・テーマは、無効化するだけでなく削除します(
wp plugin delete プラグインのスラッグ)。無効でもファイルが残っていれば、脆弱性のあるファイルに直接アクセスされることがあります。 - 長期間更新されていないプラグインや、wordpress.org で配布が止められたプラグインは、代わりを探します。
- 更新はテスト環境で確かめてから本番に入れるのが理想です。小さなサイトでは、管理画面の「プラグイン」の一覧で自動更新を有効にする方法もあります。
- 入っているプラグインの既知の脆弱性は、WPScan・Wordfence Intelligence・Patchstack などの脆弱性データベースで調べられます。
A04 暗号化の失敗
- サイト全体を HTTPS にします。手順は WordPressでSSLを有効にする方法 を参考にしてください。
wp-config.phpにdefine( 'FORCE_SSL_ADMIN', true );を書くと、ログインと管理画面が HTTPS に限られます。wp-config.phpの認証用キーとソルト(AUTH_KEYなど)は、漏えいの疑いがあるときに作り直します。作り直すと、ログイン中のユーザーは全員ログアウトします。
wp config shuffle-salts
WordPress 6.8 からは、ユーザーのパスワードの保存に bcrypt が使われています。古い独自のログイン処理やプラグインでパスワードを扱っている場合は、本体の wp_hash_password()・wp_check_password() を使っているか確認します。
A05 インジェクション
テーマやプラグインを書く人が守る基本は、「入力は無害化し、SQL はプレースホルダーで組み、出力はエスケープする」の3点です。
<?php
global $wpdb;
// 入力の無害化
$keyword = isset( $_GET['keyword'] ) ? sanitize_text_field( wp_unslash( $_GET['keyword'] ) ) : '';
// SQL はプレースホルダーで組み立てる
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->posts} WHERE post_status = %s AND post_title LIKE %s",
'publish',
'%' . $wpdb->esc_like( $keyword ) . '%'
)
);
// 出力はエスケープする
foreach ( $rows as $row ) {
printf(
'<a href="%s">%s</a><br>',
esc_url( get_permalink( $row->ID ) ),
esc_html( $row->post_title )
);
}
| 出力先 | 使う関数 |
|---|---|
| HTML の本文 | esc_html() |
| HTML の属性 | esc_attr() |
| URL | esc_url() |
| 一部の HTML を許可する本文 | wp_kses_post() |
A06 安全でない設計
- 外部に公開する機能(フォーム、REST API、Ajax)を増やすときは、「誰が」「何を」できるべきかを先に決め、最小限の権限で動くようにします。
- 会員サイトや決済など重要な機能は、プラグインを組み合わせる前に、権限とデータの流れを図にして確認します。
- 公開する必要のない REST API は REST APIへのアクセスを制限する方法 を参考に絞ります。
A07 認証の失敗
adminやwebmasterのような推測しやすいユーザー名を避けます(公式ドキュメントの推奨)。- 強いパスワードと2段階認証を使います。設定は WordPressの2段階認証の設定 を参考にしてください。
- 総当たり攻撃には、ログイン試行回数の制限が有効です(プラグインなしでログイン試行を制限する方法)。
- 使わなくなったアプリケーションパスワードは、「ユーザー」→「プロフィール」から取り消します。
A08 ソフトウェアやデータの整合性の不備
本体や wordpress.org のプラグインのファイルが改ざんされていないかは、WP-CLI で公式のチェックサムと比べて確かめられます。
wp core verify-checksums
wp plugin verify-checksums --all
- 違いが出たファイルは、改ざんか手作業での変更かを確かめます。wordpress.org 以外から入れたプラグインは比較できないので、警告として表示されます。
- プラグインやテーマは、wordpress.org か開発元の公式サイトから入手します。配布元のわからない「無料版」の有料テーマは使いません。
- 開発では、外部から受け取ったデータを
unserialize()しないようにし、JSON(json_decode())を使います。
A09 ログと警告の不備
- 管理画面での操作(ログイン、設定変更、プラグインの有効化など)を記録するプラグイン(例: WP Activity Log、Simple History)を入れると、何が起きたかを後から追えます。
- Web サーバーのアクセスログ・エラーログを保存し、
wp-login.phpやxmlrpc.phpへの大量のアクセスがないかを見ます。 - 障害調査で PHP のエラーを記録する場合は、画面に出さずにファイルへ書き出します。ログファイルは公開ディレクトリーの外に置きます。
// wp-config.php(調査のあいだだけ)
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', '/var/log/wordpress/debug.log' );
A10 例外的な状況の不適切な扱い
- 本番では PHP のエラーを画面に表示しません(
WP_DEBUG_DISPLAYをfalse、PHP のdisplay_errorsをOff)。エラーメッセージにはファイルのパスなどの内部情報が含まれます。 - WordPress 5.2 以降は、プラグインやテーマで致命的なエラーが起きると、サイトの管理者メールアドレスに「リカバリーモード」の案内が届きます。管理者メールアドレスが実際に受信できるものか、「設定」→「一般」で確認しておきます。
- 開発では、外部との通信や処理が失敗した場合の扱いも書いておきます。たとえば
wp_remote_get()の戻り値はis_wp_error()で確かめ、失敗したときに権限の確認を飛ばしたり、未完成のデータを保存したりしないようにします。
ネットワークと WAF
OWASP Top 10 の分類とは別に、サーバーの手前で攻撃を減らす方法もあります。
- サーバーのファイアウォールでは、使うポート(例: SSH・HTTP 80・HTTPS 443)だけを開け、FTP など使わないサービスは止めます。HTTP の 80 番を閉じると、HTTPS への転送や証明書の自動更新(HTTP-01 認証)が動かなくなることがあるので注意します。
- WAF(Web アプリケーションファイアウォール)を使うと、既知の攻撃パターンをサイトに届く前に止められます。導入は WAFの導入方法 や Cloudflare WAFの設定 を参考にしてください。誤って正しいアクセスを止めていないか、導入後はログを定期的に確認します。
まとめ
- OWASP Top 10:2025 は Web アプリケーション全般のリスク分類で、WordPress でも分類ごとに確認する点を当てはめられます。
- 運用では、ユーザーと権限の見直し、プラグイン・テーマの更新と削除、HTTPS、2段階認証、
DISALLOW_FILE_EDIT、ログの保存を優先します。 - 開発では、
current_user_can()と nonce、permission_callback、$wpdb->prepare()、エスケープ関数、is_wp_error()の確認を守ります。 wp core verify-checksumsやwp plugin list --update=availableで、定期的に点検します。