2026年5月30日
2026年5月30日
WordPressのSoftware and Data Integrity Failures(ソフトウェアとデータの整合性の不備)対策
WordPressでSoftware and Data Integrity Failures(ソフトウェアとデータの整合性の不備)を防ぐには、「サイトで動くコードとデータが、信頼できる出どころから改ざんされずに届いているか」を検証できる状態にすることが要点です。具体的には、プラグインの入手元と更新経路を固め、本体とプラグインのファイルをチェックサムで照合し、外部CDNのスクリプトにSRIを付け、信頼できないデータを unserialize() しない、の4つが柱になります。この記事では、それぞれの設定方法と、改ざんに気づくための定期チェックの組み方を解説します。
Software and Data Integrity Failuresとは
Software and Data Integrity Failuresは、Webアプリケーションの代表的なリスクをまとめた OWASP Top 10 の分類の1つで、2021年版で A08 として加わりました。2025年版でも A08 に「Software or Data Integrity Failures」として残っています(2026年10月現在)。中身をひと言でいえば、「検証していないコードやデータを信用してしまうこと」です。
WordPressに当てはめると、次のような場面が該当します。
- 配布元が不明なプラグインやテーマ(いわゆる nulled 版)を入れ、仕込まれたバックドアごと動かしてしまう
- サーバー上のファイルが書き換えられても気づけない
- CDNから読み込む JavaScript が差し替えられても、そのまま実行してしまう
- Cookie やフォームから受け取ったシリアライズ文字列を
unserialize()し、任意のオブジェクトを生成されてしまう - 誰でも変更できるデプロイ手順や、バージョンを固定していない依存パッケージから本番に反映してしまう
SQLインジェクションのように1つの入力欄の問題ではなく、「どこから来たものを信用しているか」という仕組みの問題なので、入口ごとに確認していきます。
プラグイン・テーマの入手元と更新経路を固める
最初に見直すのは、コードの出どころです。
公式ディレクトリ(WordPress.org)のプラグインとテーマは、WordPress.org から HTTPS で配布され、更新も同じ経路で届きます。市販のプラグインは開発元の公式サイトやマーケットプレイスから入手し、ライセンス認証による正規の更新を受けます。有料プラグインを無料で配布しているサイトのファイルは、改変されている前提で扱い、導入しないでください。
本体については、WordPress 5.2 以降、更新パッケージの署名を検証する仕組みが組み込まれています。署名や配布の仕組みを活かすためにも、管理画面からの通常の更新を使い、ZIPを手作業で差し替える運用は避けます。
自作プラグインを社内で配布している場合は、プラグインのヘッダーに Update URI を書いておきます。WordPress 5.8 で追加された項目で、WordPress.org に同じスラッグのプラグインがあっても、そちらの更新で上書きされるのを防げます。
<?php
/**
* Plugin Name: My Company Tools
* Version: 1.4.0
* Update URI: false
*/
false を指定すると、WordPress.org の更新確認の対象から外れます。独自の配布サーバーから更新を届けたい場合は、そのURLを指定し、更新処理を自前で実装します。
あわせて、管理画面からのファイル編集を止めておくと、管理者アカウントが乗っ取られたときにテーマやプラグインのPHPを書き換えられにくくなります。
// wp-config.php(「編集が必要なのはここまでです」の行より上に書く)
define( 'DISALLOW_FILE_EDIT', true );
DISALLOW_FILE_MODS を true にすると、プラグインの追加や更新も管理画面からできなくなります。更新をWP-CLIやデプロイで行う運用が整っている場合だけ使い、そうでなければ更新が止まって逆に危険になる点に注意します。
本体とプラグインのファイルをチェックサムで照合する
サーバー上のファイルが配布元と同じかどうかは、WP-CLIで確かめられます。
cd /var/www/html
# WordPress 本体
wp core verify-checksums
# WordPress.org で配布されているプラグイン
wp plugin verify-checksums --all
本体のチェックでは、wp-admin と wp-includes などのファイルが、インストールされているバージョンの公式のチェックサムと照合されます。書き換えられたファイルは「File doesn't verify against checksum」、本来存在しないファイルは「File should not exist」という警告で表示されます。wp-includes に見覚えのないPHPファイルがある場合は、改ざんを疑って調べます。
プラグインのチェックは、WordPress.org にチェックサムが公開されているものだけが対象です。市販プラグインや自作プラグインは照合できずスキップされるため、別の方法で基準を作ります。たとえば、正常な状態のときにハッシュの一覧を保存し、後で比べます。
# 正常な状態の一覧を保存(保存先は Web から見えない場所に)
cd /var/www/html/wp-content
find plugins/my-premium-plugin themes/my-theme -type f -name '*.php' -print0 \
| sort -z | xargs -0 sha256sum > /root/wp-baseline.sha256
# 後日、差分を確認する
sha256sum --quiet -c /root/wp-baseline.sha256
--quiet を付けると、一致しないファイルだけが表示されます。プラグインを更新したら基準も取り直します。取り直さないと、正当な更新まで改ざんとして表示されてしまいます。新しく追加されたファイルはこの方法では検出できないため、ファイル数の変化や wp-content/uploads 内のPHPファイルの有無もあわせて確認すると安心です。
find /var/www/html/wp-content/uploads -type f -name '*.php'
定期実行して異常だけ通知する
手動の確認は続かないので、cron で毎日実行し、問題があったときだけ通知するようにします。WP-CLI は、照合に失敗したときに0以外の終了コードを返します。
#!/bin/bash
# /usr/local/bin/wp-integrity-check.sh
cd /var/www/html || exit 1
if ! OUT=$( { wp core verify-checksums && wp plugin verify-checksums --all; } 2>&1 ); then
echo "$OUT" | mail -s "[WordPress] checksum mismatch on $(hostname)" admin@example.com
fi
# Web サーバーの実行ユーザーで毎朝4時に実行する例(crontab -u www-data -e で登録)
# cron の PATH は最小限なので、wp が /usr/local/bin にあるなら PATH を指定しておく
PATH=/usr/local/bin:/usr/bin:/bin
0 4 * * * /usr/local/bin/wp-integrity-check.sh
mail コマンドが使えない環境では、Slack の Webhook など普段見ている通知先に置き換えます。root で WP-CLI を動かすと警告が出るうえ、生成されたファイルの所有者が変わることがあるため、Webサーバーと同じユーザーで実行します。
外部から読み込むJavaScriptにSRIを付ける
CDNから読み込むライブラリは、CDN側で差し替えられるとサイト上でそのまま実行されます。SRI(Subresource Integrity)を付けると、ブラウザーがファイルのハッシュを確認し、一致しなければ実行しません。
まずハッシュを求めます。URLはバージョンを固定したものを使います。latest のように中身が変わるURLにSRIを付けると、更新のたびに読み込めなくなります。
curl -s https://cdn.jsdelivr.net/npm/example-lib@1.2.3/dist/example.min.js \
| openssl dgst -sha384 -binary | openssl base64 -A
WordPressの wp_enqueue_script() には integrity を指定する引数がないため、script_loader_tag フィルターで属性を追加します。
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_script(
'example-lib',
'https://cdn.jsdelivr.net/npm/example-lib@1.2.3/dist/example.min.js',
array(),
null, // ?ver= を付けない
true
);
} );
add_filter( 'script_loader_tag', function ( $tag, $handle, $src ) {
if ( 'example-lib' !== $handle ) {
return $tag;
}
$integrity = 'sha384-REPLACE_WITH_REAL_HASH'; // 上のコマンドで得た値に置き換える
return str_replace( ' src=', ' integrity="' . esc_attr( $integrity ) . '" crossorigin="anonymous" src=', $tag );
}, 10, 3 );
crossorigin="anonymous" が無いと、ブラウザーは別ドメインのファイルのハッシュを検証できず、読み込みに失敗します。設定後はブラウザーの開発者ツールでページのソースを開き、属性が付いていることと、コンソールに integrity のエラーが出ていないことを確認します。
信頼できないデータをunserializeしない
PHPの unserialize() は、文字列からオブジェクトを復元します。利用者が送れる値(Cookie、フォーム、REST APIのパラメーターなど)を渡すと、プラグインに含まれるクラスを悪用されて任意のコードを実行される「PHPオブジェクトインジェクション」につながります。WordPressの maybe_unserialize() も中で unserialize() を呼ぶため、外部から来た値に使うのは同じく危険です。
利用者とやり取りするデータは JSON にし、受け取った後に型と値を確認します。
// 避けるべき例: Cookie の値をそのまま復元している
// $prefs = unserialize( base64_decode( $_COOKIE['myplugin_prefs'] ) );
// JSON で受け取り、想定した値だけを使う
$layout = 'grid';
if ( isset( $_COOKIE['myplugin_prefs'] ) ) {
$decoded = json_decode( wp_unslash( $_COOKIE['myplugin_prefs'] ), true );
if ( is_array( $decoded ) && isset( $decoded['layout'] ) && in_array( $decoded['layout'], array( 'grid', 'list' ), true ) ) {
$layout = $decoded['layout'];
}
}
古いデータの互換性などでどうしても unserialize() を使う場合は、第2引数に array( 'allowed_classes' => false ) を指定し、オブジェクトを復元させないようにします。
デプロイと依存パッケージの整合性
Gitやデプロイツールで本番に反映している場合は、その経路も整合性の対象です。
- Composer を使うプロジェクトでは
composer.lockをリポジトリに含め、本番ではcomposer installで記録どおりのバージョンを入れます。composer auditで既知の脆弱性がある依存パッケージも確認できます。 - npm でビルドしている場合も、
package-lock.jsonを含め、CI ではnpm ciを使います。 - 本番に反映できる人と仕組みを限定し、デプロイ用の鍵やトークンは CI のシークレットに保管します。
バックアップもデータの整合性の一部です。取得したファイルの sha256sum を一緒に保存しておくと、復元前に壊れていないかを確かめられます。ステージング環境に実際に復元できるかを定期的に試しておくと、いざというときに慌てずに済みます。
まとめ
- Software and Data Integrity Failures は「検証していないコードやデータを信用すること」によるリスクです。入手元、サーバー上のファイル、外部スクリプト、利用者からのデータ、デプロイ経路の順に確認します。
- プラグインは正規の配布元から入手し、社内プラグインには
Update URIを指定し、DISALLOW_FILE_EDITで管理画面からの編集を止めます。 wp core verify-checksumsとwp plugin verify-checksums --allを cron で定期実行し、照合できない市販・自作プラグインはハッシュの基準ファイルで比べます。- CDNのスクリプトはバージョンを固定し、
script_loader_tagで integrity と crossorigin を付けます。 - 外部から来た値は
unserialize()せず JSON で扱い、依存パッケージはロックファイルで固定します。