侵害されていないかを確かめる3つの点検 — チェックサム・管理者アカウント・uploads の PHP
更新を当てるのは「入れない」ための作業だ。では、すでに入られていないかは、どう確かめるのか。この記事では、WP-CLI で実行できる3つの点検 — 本体・プラグインのチェックサム検証、管理者アカウントの棚卸し、uploads 配下の PHP ファイル確認 — を、見方と限界まで含めて整理する。点検は防御のための作業であり、「異常なし」が安全の保証になるわけではない。その前提で読んでほしい。
なぜ「入られていないか」を確かめるのか
更新を当て、不要なプラグインを消しても、それは「これから入られにくくする」作業にとどまる。更新の公開から悪用までの時間が短くなっているという調査もある(公開から悪用までの時間の記事 で一次情報を確認した)。更新の前に何かが入っていた可能性は、ゼロにはできない。
そこで保守には、もう1つの視点が要る。今ある状態が、本来あるべき状態と一致しているか を定期的に確かめることだ。ここで挙げる3つは、どれも読み取り専用のコマンドで、サイトの状態を変えない。
| 点検 | 確かめること | 主なコマンド |
|---|---|---|
| ① ファイルの一致 | 本体・プラグインのファイルが配布元のものと同じか | wp core verify-checksums / wp plugin verify-checksums |
| ② アカウント | 見覚えのない管理者がいないか | wp user list --role=administrator |
| ③ 置き場所 | 本来コードが置かれない場所に PHP がないか | find による uploads/ の確認 |
① チェックサムで「配布元と同じか」を確かめる
ハッシュ関数とチェックサムの基礎で書いたとおり、ファイルの内容が1文字でも違えばハッシュ値は大きく変わる。WP-CLI は、この仕組みを WordPress の点検に使っている。
wp core verify-checksums
このコマンドは WordPress.org から、インストールされているバージョンの MD5 チェックサム一覧を取得し、手元のファイルと突き合わせる。公式のコマンド説明によれば、検証時には WordPress 本体を読み込まない。つまり、改ざんされたコードが動かないまま検証できる設計になっている。
問題がなければ、次のように表示される。
Success: WordPress installation verifies against checksums.
食い違いがあると、ファイルごとに「チェックサムと一致しない」「存在すべきでないファイルがある」といった警告が並ぶ。
見方のポイントは3つある。
- ロケールとバージョン: 日本語版は配布物が英語版と異なるため、うまく検証できないときは
--localeと--versionを管理画面の「更新」画面の値に合わせる - ルート直下: 既定では
wp-content以外の本体ファイルが対象になる。ルート直下に置かれた見慣れないファイルまで見たいときは--include-rootを付ける - 自分で書き換えた場合: 本体ファイルを直接編集していれば、当然「一致しない」と出る。なぜ一致しないのかを自分で説明できるかが、判断の分かれ目になる
プラグインも同様に検証できる
wp plugin verify-checksums --all
WordPress.org のディレクトリで配布されているプラグインについては、同じ方式で検証できる。ここで大事なのは 「確認できなかったもの」を見落とさない ことだ。有償プラグインや、公式ディレクトリ外で配布されているプラグインにはチェックサムが無く、「検証できない」と表示される。これは異常ではない。ただし、その分だけ点検の穴がある と受け取るのがよい。
「4つ中4つ検証できた」という結果は、その4つについて安心材料になる。検証対象外のものは、別の手段(開発元の更新履歴の確認、ファイルの更新日時の確認など)で補う。
チェックサム検証にできないこと
- テーマやプラグインのうち、チェックサムが公開されていないもの は確認できない
wp-config.php、uploads/、自分で作ったファイル は、配布元に正解が無いため対象外- データベースに入った内容(投稿やオプションに紛れ込んだ不正なコード)は、ファイルの検証では見えない
- 一致していても、配布元自体が改ざんされた場合 (T79) は検出できない
「一致した」は「配布元と同じだった」という意味であり、「安全だ」という意味ではない。
② 管理者アカウントを棚卸しする
侵入が起きた場合に残りやすい痕跡の1つが、見覚えのない管理者アカウント だ。パスワードを変更しても、そのアカウントが残っていれば、そこが新しい入口になり続ける。
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
--role で役割を絞り、登録日時(user_registered)まで並べて見る。確認する観点は次のとおり。
- 全員を説明できるか: 管理者が誰で、何のために必要かを言えるか
- 登録日時に心当たりがあるか: 自分が作業していない時期に作られたアカウントはないか
- メールアドレスが想定どおりか: 退職した人、過去の制作会社、使っていないメールが残っていないか
- 管理者が多すぎないか: 必要な権限は、管理者でなく「編集者」で足りることも多い
見覚えのないアカウントが見つかっても、その場で削除しない のがよい。後述する初動のとおり、削除すると手がかりが消える。まず状況を記録する。
そもそも管理者は少ないほどよい。使っていないアカウントは、権限を下げるか削除する、という整理を定期的に行うだけで、入口は減る。
③ uploads 配下に PHP ファイルがないか確かめる
wp-content/uploads/ は、メディアライブラリにアップロードされた画像や PDF を置く場所だ。通常は、ここに PHP ファイルは存在しない。 画像やドキュメントの置き場に、実行されるコードがあるのは不自然だからだ。
確認は、読み取りだけで済む。
find wp-content/uploads -type f -name '*.php'
何も表示されなければ、この観点では問題が見つからなかったことになる。表示された場合は、次のように考える。
- 全く心当たりがない: 扱いに注意する。中身を開いて実行したりせず、パスと更新日時を記録する
- プラグインが意図して置いている: 一部のプラグインは、uploads 配下に生成物を置く。その場合は何のプラグインのものか、説明できるかを確認する
なお index.php(中身がほぼ空のもの)が置かれているケースがある。これは、ディレクトリの一覧表示を防ぐ目的で置かれる慣習的なファイルで、内容を確認すれば見分けがつく。
さらに踏み込むなら、そもそも uploads で PHP が実行されない設定にしておく 手がある。これは「入口を減らす」側の話で、サーバーごとに設定方法が異なる。詳細は次回以降の記事でまとめる予定だ。
点検を日常の運用に組み込む
3つは、単発で行うよりも 定期的に同じ手順で行い、前回との差を見る ほうが役に立つ。
- 実行日と結果(成功・警告の内容)を記録しておく
- 警告が出たら、「なぜ出たか」を説明できるまでは「問題なし」と扱わない
- 更新の直後にも実行する(更新によって、見慣れない変更が入っていないかを見る)
複数のサイトを持っている場合は、wp-cli aliases のようにサイトを切り替えて同じコマンドを回すと、手順が揃う。ただし、結果の確認と判断は、1サイトずつ自分の目で行う。
異常が見つかったら
何か引っかかったときは、まず次の順で考える。
- 状況を記録する(コマンド、出力、時刻)。ここで削除や上書きをしない
- それが本当に異常か を確認する(自分の変更、プラグインの正規の動作ではないか)
- 異常と思われる場合は、復旧を含めた初動に移る。バックアップがあるか、クリーンな状態へ戻せるか が分かれ目になる
初動の詳しい手順は、別の回で扱う。判断に迷う場合は、専門の窓口に相談するのがよい。
まとめ
- 更新は「これから」を守る作業。すでに入られていないか を確かめる点検が、保守のもう半分になる
wp core verify-checksums/wp plugin verify-checksumsは、配布元のハッシュと突き合わせる。検証できないものがある ことも、結果の一部として受け取る- 管理者アカウントは
wp user list --role=administratorで棚卸しし、全員を説明できる状態に保つ uploads/に PHP があるのは通常は不自然。見つかったら、実行せずに記録する- どの点検も「異常なし=安全」ではない。前回との差を見る習慣 にすると役に立つ
今日できる一手は、wp user list --role=administrator を実行して、全員の名前と存在理由を説明できるか を確かめること。