断続的なバグは、デバッグの最も基本的なステップである「狙って再現する」ことができないため、最も診断しにくい種類のものです。あるストアのカートドロワーの「商品を削除」ボタンが、一部の訪問者に対して、ときどき 403 Forbidden エラーで失敗していました。PHP のエラーログにも原因を示す有用な情報はありませんでした。
失敗の特徴を読み取る
AJAX リクエストのレスポンス本文はただの -1 で、HTTP ステータスは 403 でした。この組み合わせは、WordPress で check_ajax_referer() の呼び出しが失敗したときの特徴そのものです。これは、正しく作られた AJAX ハンドラーが何よりも先に行うセキュリティ用 nonce の検証です。ページが送った nonce が、サーバーの期待するものと単純に一致していませんでした。
本来は有効な nonce が失敗しうる理由
WordPress の nonce は永続的なものではありません。ページを読み込むたびに生成され、固定値ではなく移り変わる時間枠に結び付いていて、およそ 24〜48 時間で期限切れになります。ところが、このサイトの LiteSpeed のページ全体キャッシュは TTL が 7 日に設定されていました。つまり、キャッシュされたページが、生成から最長 1 週間、変更されないまますべての訪問者に配信されうる状態でした。
キャッシュされてから約 2 日以上たってもキャッシュから配信されていたページは、実際の訪問者が使おうとした時点ですでに期限切れの nonce を渡していました。その訪問者のセッションに問題があったのではなく、HTML そのものが WordPress のセキュリティ上の時計に対して古くなっていたのです。
修正方法と、それが回避策ではなく本当の修正である理由
ページキャッシュの TTL を、WordPress の nonce の最短有効期間を十分に下回る 6 時間に下げたところ、すぐに完全に解決しました。症状を覆い隠すのではなく、実際のずれそのものに対処したからです。調査の過程で、決済ページにあった無関係で重複したカート表示も削除しました。決済ページの注文確認にすでに同じ情報が表示されていたためです。
ポイントのまとめ
- レスポンス本文が
-1で HTTP 403 なら、WordPress の nonce チェック失敗の指紋のようなものです。ひと目でわかるようにしておく価値があります。 - ページ全体キャッシュの TTL と WordPress のセキュリティトークンの有効期間は、互いに整合させる必要がある 2 つの設定ですが、初期状態ではそれを強制する仕組みはありません。
- 断続的で一見ランダムなバグは、それぞれ単体では正しく動いている 2 つのシステムの間のタイミングのずれであることがよくあります。
関連記事:6 時間のタイムスタンプのずれ、Web サイト保守で実際に行うこと。
ご自身の WooCommerce や WordPress の管理画面で同じような制約にお困りですか?ご相談ください。ArtinTech Solution はまさにこうしたストア向けのカスタムツールを開発しています。