WordPressサイトのURLに ?doing_wp_cron= という見慣れないパラメータが出現。お客さんから「URLに変な文字列があるんだけど?」と指摘されたり、Google Analyticsでパラメータ付きURLが記録されて気づくケースが多いのではないでしょうか。
このパラメータはWordPressの内部タスクスケジューラ「wp-cron」が使っています。この記事では、doing_wp_cronの仕組みとセキュリティ上どうなのかの解説、そしてサーバーcronで代替する設定方法を説明します。
doing_wp_cronの正体
WordPressには「WP-Cron」という疑似的なタスクスケジューラが組み込まれています。予約投稿の公開やバックアップなど、定期的な処理を管理する仕組みです。WP-Cronが起動する際に、このタイムスタンプがURLパラメータとして付与されます。これが、doing_wp_cronの正体です。
doing_wp_cronの後ろの長い数字はUnixタイムスタンプで、cron実行の排他制御(ロック)に使われる値です。URLによって起動されるが、複数起動しては困るため、排他制御しているんですね。
ではなぜ、内部的な値がサイト閲覧者の目に触れるのか。原因は ALTERNATE_WP_CRON という代替実装にあります。
なぜURLに?doing_wp_cron=が表示されるのか
WP-Cronのデフォルト動作では、WordPressがサーバー内部で自分自身の wp-cron.php にHTTPリクエストを送ります(ループバックリクエスト)。この方式ならリクエストはサーバー内で完結し、閲覧者のブラウザには影響しません。
しかし、サーバー環境によってはこのループバックリクエストが失敗します。その代替として用意されているのが ALTERNATE_WP_CRON です。このALTERNATE_WP_CRON が有効なサイトでは、URLに ?doing_wp_cron= パラメータが付くことがあります。
ALTERNATE_WP_CRON が有効な場合、WordPressは以下の処理を行います。
wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
注目すべきはユーザーが今アクセスしているページのURLに ?doing_wp_cron= を付けてリダイレクトしている点です。たとえば https://example.com/about/ にアクセスすると、https://example.com/about/?doing_wp_cron=1656423456.789… にリダイレクトされます。
ページ自体は通常通り表示されますが、URLバーにはパラメータが残ったままになります。
URLに残ることの実害
doing_wp_cronには、お客さんから問い合わせが来てしまう以外の弊害もあります。
- Google Analyticsのデータ分散: パラメータ付きURLが別ページとして集計され、PVやセッションデータが分かれる
- 検索エンジンへの影響: パラメータ付きURLがインデックスされると、重複コンテンツとして扱われる可能性がある
- ブックマーク・共有の問題: ユーザーがパラメータ付きのままURLをブックマーク・共有してしまう
これらを避けるにはどうしたらよいでしょうか。
WP-Cronの仕組み
その前に、WP-Cronの動作をもう少しくわしく理解しましょう。LinuxのcronがOSレベルで時刻を監視し指定時刻にタスクを自動実行するのに対し、WP-Cronは「誰かがサイトにアクセスしたタイミング」でスケジュールを確認し、期限が来たタスクを実行するアクセストリガー型の仕組みです。
| サーバーcron | WP-Cron | |
|---|---|---|
| トリガー | 時刻(OS管理) | サイトへのアクセス |
| 実行精度 | 指定時刻に正確 | アクセス依存で遅延あり |
| アクセスがない時間帯 | 実行される | 実行されない |
リクエストが届くと、スケジュール済みタスクの実行時刻をチェックし、期限を過ぎたタスクがあればcron処理を起動します。対象となるのは予約投稿の公開、プラグイン・テーマの自動更新チェック、メール送信キューなどです。
アクセスがなければcronは動きません。深夜にアクセスがほぼゼロのサイトでは、午前0時の予約投稿が翌朝の最初のアクセスまで公開されないこともあります。
doing_wp_cron のセキュリティリスクはあるか?
WordPressのcron処理を担うwp-cron.php は、WordPressのインストールディレクトリ直下に置かれた実行可能なPHPファイルです。デフォルトではインターネットから誰でもアクセスできる状態にあります。
悪意のある第三者が https://example.com/wp-cron.php に大量のリクエストを送ると、アクセスのたびにWordPressの起動処理が走ります。
WP-Cron自体には60秒間のロック機構があるため、スケジュールタスクが毎回実行されるわけではありません。しかし、起動処理だけでもリソースを消費するので、サーバーに負荷をかけるDoS的な攻撃に利用される可能性があります。
WP-Cronを止めてサーバーcronに切り替える方法
WP-Cronを無効化してサーバーcronに置き換えれば、?doing_wp_cron= パラメータの露出を防ぎつつ、定時実行の確実性とセキュリティを向上できます。手順は「WP-Cronの無効化」「サーバーcronの設定」「外部アクセスの制限」の3ステップです。
レンタルサーバー(共用サーバー)ではOSのcrontabを使えないことがありますが、管理画面のcron設定機能や外部cronサービスで代替できる場合があります。
wp-config.phpでWP-Cronを無効化する
wp-config.php に以下の1行を追加します。/* That’s all, stop editing! */ というコメントより上に記述してください。
define( 'DISABLE_WP_CRON', true );
ALTERNATE_WP_CRON が定義されている場合は、あわせて削除またはfalseに変更しておきましょう。
サーバーcronでwp-cron.phpを定期実行する
WP-Cronを無効化しただけでは、予約投稿や自動更新が止まってしまいます。代わりにサーバー側から定期的にcronタスクを実行する設定を入れます。
WP-CLIが使える環境(推奨)
*/15 * * * * cd /var/www/html && wp cron event run --due-now --quiet
WP-CLIの wp cron event run –due-now は、実行期限が来ているイベントだけを処理します。ただしインストールパスがわかる人でないと使えません。
WP-CLIが使えない環境
*/15 * * * * curl -sS https://example.com/wp-cron.php > /dev/null 2>&1
curl でHTTPアクセスする方法です。この場合、次のステップで設定するアクセス制限との兼ね合いに注意してください。
curlの実行元がlocalhost(同一サーバー)であれば制限に引っかかりませんが、外部サーバーからcurlを叩く構成では、そのIPアドレスをApacheの Require ip やNginxの allow ディレクティブに追加する必要があります。
実行間隔は15分が一般的です。予約投稿を分単位で正確に公開したい場合は5分間隔にするとよいでしょう。
wp-cron.phpへの外部アクセスを制限する
サーバーcronで内部から実行する設定にしたら、外部からの直接アクセスを塞ぎます。
Apacheの場合(.htaccess)
<Files wp-cron.php>
Require local
</Files>
Nginxの場合
location = /wp-cron.php {
allow 127.0.0.1;
allow ::1;
deny all;
}
WP-CLIで実行している場合はHTTP経由ではないので、このアクセス制限の影響を受けません。
切り替え後の確認と注意点
設定を変更したら、予約投稿が正しく公開されるかテストしてください。適当な時刻に予約投稿を作成し、cronの実行タイミングを過ぎた後に公開されていれば正常です。
プラグインのスケジュールタスクが動いているかどうかは、WP Crontrolプラグインで確認できます。管理画面の「ツール」→「Cron Events」から、登録済みのイベント一覧と次回実行時刻を確認できるので、切り替え直後に一度チェックしておくと安心です。
まとめ
?doing_wp_cron= は、WP-Cronが実行された際に付与されるタイムスタンプです。ALTERNATE_WP_CRON が有効な環境では閲覧者のURLにこのパラメータが表示され、Google Analyticsのデータ分散や検索エンジンへの悪影響を招きます。WP-Cronを無効化してサーバーcronに切り替えれば、パラメータの露出を防ぎつつ、タスク実行の安定性とセキュリティも向上します。
