セキュリティをどう向上させるべきか
運用しているWordPressのセキュリティについて説明を求めたとき、「最新版に更新しています」「セキュリティプラグインを導入しています」などの定性的な回答しか返ってこないと「ほんとうに安全なのか」という不安がつきまといます。その一方で「絶対に安全です」と言い切られることもまた不安です。攻撃手法は日々巧妙化しており、昨日まで存在しなかった脆弱性が今日発見される可能性は常に存在します。
この状況を説明するのに便利なのが、スイスチーズモデルです。事故分析の分野で提唱されたモデルで、防御を「穴の空いたチーズのスライス」に見立てます。どの層にも穴があり、完全な防御層は存在しません。しかし複数の層を重ねれば、穴が一直線に並ぶ確率は下がります。事故が起きるのは、すべての層の穴が偶然一致したときです。

具体的な脆弱性の穴が塞がれているかをチェックし、その検出結果の量で安全性を担保するという計量的なアプローチはセキュリティ品質が向上していることを示すよい指標になるでしょう。
WordPressのセキュリティで注意すべき観点
WordPressは安全なソフトウェアですが、一般的なWebサイトと比較して、以下のような注意点があります。
- 第三者が書いたコードへの依存度が高いこと。プラグインとテーマは、その多くが外部の開発者によるものです。自社で書いていないコードが本番環境で動いているという構造は特徴的です。
- 構成要素が多く、更新が頻繁であること。コア、プラグイン、テーマがそれぞれ独立して更新されます。診断した時点では問題がなくても、翌週には新しい脆弱性情報が公開されているのが普通です。
- 管理画面が強力であること。管理画面に入ることができれば、プラグインやファイルを追加できます。ファイルを編集できる状態(
DISALLOW_FILE_EDITがtrueではない)であれば、管理者アカウントの奪取はサーバー上での任意コード実行と同義です。権限設計が診断項目になるのは、この構造に由来します。
なお「シェアが高く狙われやすいのでセキュリティ対策をすべき」という論点については、セキュリティに弱いWordPressとセキュリティに強いWordPressの違いおよび公式情報から考えるWordPressのセキュリティへの取組みで詳しく扱っています。
WordPressで脆弱性になりやすいところ
多層防御を設計するには、まず「どのチーズに穴が空きやすいか」を知る必要があります。WordPressサイトで繰り返し問題になる箇所を整理します。
汎用的なリスク
Webアプリケーション全般に共通する項目です。OWASP Top 10や、IPAの『安全なウェブサイトの作り方』が体系的な一覧を提供しています。
| リスク | 内容 |
|---|---|
| SQLインジェクション | データベースへの不正な命令の実行 |
| クロスサイトスクリプティング(XSS) | 閲覧者のブラウザ上での不正なスクリプト実行 |
| CSRF | 意図しない操作を第三者に実行させる |
| OSコマンドインジェクション | サーバー上での任意コマンドの実行 |
| 認証・認可の不備 | なりすまし、権限を超えた操作 |
| 機密情報の露出 | 公開すべきでない情報へのアクセス |
上記は基本的な知識ではありますが、たとえばWordPress制作の依頼をする立場の方であれば、「IPAの『安全なウェブサイトの作り方』にのっとって開発してください』と言い添えるだけでも防御層が増えることになります。
OS・ミドルウェア・データベースの既知脆弱性
WordPressが動作するためには、Apache, NginxなどのWebサーバー、データベース(MySQL, MariaDB)、OS(Ubuntu, Amazon Linux)などの環境が必要です。もちろん、これらにも脆弱性は存在することがあります。
基本的な対策としては定期的にアップデートを行うこと以外にありません。マネージドホスティングやレンタルサーバーなどでは脆弱性が出た場合は周知の上で更新してくれることが多いため、あまり気にする機会もないでしょう。注意すべきは自社管理のケースです。たとえばAmazon Web Serviceのようなクラウドホスティングでは、AWS System Managerのように、「脆弱性データベースを検証して必要なパッチを当てる機能」が存在しますが、これらを利用していない場合は定期的に更新をするなどのルールを設定すべきでしょう。
プラグイン・テーマの既知脆弱性
最も多い経路です。WordPressはファイルパスやreadme.txtから使用しているプラグインとそのバージョンが特定できます。よくある対策として「 head > meta=generator に表示されているWordPressバージョンを隠す」という方法が知られていますが、攻撃者はそもそも「このサイトは古いWordPressだな」と確認してから攻撃をするとは限りません。攻撃者は「特定のバージョン以下なら必ず通じる攻撃」を膨大な数のサイトに当てずっぽうで行うのです。10,000回攻撃して、10件あたれば成功、と考えています。
対策としてはできる限り迅速にアップデートを行うこと。自動アップデートの採用も考慮に入れましょう。
権限とロールの設計
WordPressの権限はユーザーではなくロール(役割)に紐づいています。実務で最も多い問題は、必要以上に管理者権限を持つユーザーの存在です。技術的な脆弱性ではありませんが、ファイル編集機能を無効にしていない( DISALLOW_FILE_EDIT が true でない )場合、管理者アカウントが任意コード実行と同義であることを踏まえれば、確実にリスクです。
すべてのユーザーを「管理者」として登録するのではなく、役割に応じて「編集者」「投稿者」などを使い分けましょう。これは運用だけで高められるセキュリティです。Two Factorなどの多要素認証プラグインの導入もあわせてお勧めします。
著者アーカイブとユーザー名の露出
WordPressは /?author=1にアクセスすると著者アーカイブにリダイレクトされ、URLにuser_nicenameが現れます。初期設定のままだとログイン名と一致します。WordPressコアチームはユーザーログイン名を「秘匿情報ではない」と考えていますが、セキュリティの観点からは「ユーザー名がわからない方がパスワードだけがわからない場合よりも確率的に堅牢なのでは?」と反論することもできます。
また、サイトの方針として「そもそもWordPressのユーザー名を出したくない」というケースも存在します。WordPressの基本概念では「投稿者=記事の作者」ですが、エンタープライズの現場では「記事を書いた人と入稿する人が別」というケースはよくあります。これはセキュリティリスクではありませんが、「情報漏洩」と考えるサイト運用者は存在するでしょう。
WordPressは次のような経路でユーザー名を表示します。
- 著者アーカイブ
- REST APIの
/wp-json/wp/v2/usersからは、公開済みの投稿を持つユーザーの一覧が取得できます - YoastのようなSEOプラグインでは、
metaタグとしてauthorを出力します
タロスカイではこれに対応した Hide Author Archive というプラグインをメンテナンスしています。
ファイルアップロードとメディア処理
WordPressではファイルをアップロードできますが、アップロードされるファイルが必ずしも安全とは限りません。また、単体で無害(例・スクリプトを実行できるSVGファイルがアップロードできる)であっても、他の脆弱性(例・誰でも投稿者になれる権限昇格バグ)と組み合わされることで危険な結果をもたらすことがあります。
wp-content/uploads/ でPHPが実行可能になっていないか、許可するMIMEタイプが広すぎないか、などは常に注意しておく必要があります。
設定ファイルとバックアップの残留
wp-config.php.bak、.git/config、database.sqlのような、開発や運用の過程で生まれるファイルが公開ディレクトリに残っていないか。これらは攻撃者の自動スキャンで必ず試行されるパターンです。
著名なプラグインであっても、デフォルトでは wp-content 以下、つまり公開領域にバックアップファイルを保存し、.htaccess でファイルを保護する仕様であることは珍しくありません。サーバー環境(例・Webサーバーがnginx)によってはデフォルトで期待される保護機能が動かないこともありえます。ある程度の知名度を誇るプラグインであれば非公開領域にバックアップを保存する設定が用意されているはずなので、細かく設定を確認しましょう。
ログイン試行とxmlrpc.php
wp-login.phpもまたWordPressが槍玉に挙げられる機能です。実際、アクセスログなどを眺めるとwp-login.phpへの攻撃を観測できるはずです。
また、 xmlrpc.php も攻撃対象になります。おそらくですが、wp-login.phpよりもxmlrpc.phpの方が攻撃対象としては「有望」です。仕様上複数リクエストをまとめて送れることなどが原因で、機械的に大量のユーザー名・パスワードを送りつけることができるからです。すでに漏洩した認証情報のセットが通じるかどうかを試すリスト攻撃や、よくある組み合わせ(admin/password)を大量に試す辞書攻撃の餌食になります。
対策は以下の通りです。
- 多要素認証の導入
- reCaptchaやCloudFlare Turnstileなどの導入
- xmlrpc.phpをアクセス遮断(Jetpackを使わないなら遮断可能)
- 極端に多い試行をブロック
- Basic認証の導入(ブルートフォースで破られるが、4と組み合わせれば問題ない)
診断項目には現れないが、穴になるもの
見落とされやすい領域です。技術的な検査では検出できませんが、運用体制が結果的に脆弱性へ繋がることがありえます。
- 誰がいつ何を変更したかを追跡できない(監査ログの不在)
- インシデント発生時に誰がどう動くか決まっていない
- 更新の適用手順が属人化している
- 退職者のアカウントが残っている
監査ログはプラグイン(Streamなど)で対応できますが、その他は運用体制でカバーする必要があります。
チーズの層とその穴
スイスチーズモデルで言う「層」は、システムのスタックに対応します。攻撃が外側から入ってくる順に並べます。
- ネットワーク層:CDNなどを使っている場合、ここで防御を行うことが可能です。WAFを利用していればSQLインジェクションなどの既知の攻撃を自動的にブロックしてくれます。もっとも費用対効果が大きい防御層だと言えるでしょう。
- OS・ミドルウェア層:OSやミドルウェアにもセキュリティ機能が存在します。しかし、細かな設定を行うには知識が必要です。
- WordPress層:WordPressにもセキュリティ機能は存在し、脆弱性も発見され次第潰されていきます。ただし、自動更新が適用されていることが条件です。
- プラグイン層:もっとも脆弱性が出やすい層です。他のセキュリティ層によって守ってもらうべき箇所といえるでしょう。
- カスタムコード層:自作テーマやプラグインなどのカスタムコードが存在する場合、WordPressのセキュリティ機能の一部(WP CLIのチェックサム確認など)は利用することができません。開発者のレベルによって一番脆弱性が入り込みやすい箇所でもあります。
上記のうち、1-3まではすでに述べた通り常に最新版を適用するという単純な原則で対応することができます。難しいのは4,5です。
プラグインのセキュリティを担保する方法
プラグインはWordPressに拡張性をもたらし、ある意味でWordPressが世界中で使われるようになった中心的なシステムでもあります。「プラグインがWordPressの魅力だが脆弱性が仕込まれやすいのもプラグイン」という状況にはWordPressプラグインレビューチームも危機感を持っており、さまざまな対策がなされています。
- プラグインをチェックしてくれるプラグイン、Plugin Check。プラグインディレクトリに新しいプラグインを導入する前に実行することが推奨されています。もちろん、公開予定のないプラグインに対しても使うことができます。
- WP CLIのチェックサム確認。WordPress.orgで配布されているプラグインに限り、
wp plugin verify-checksums --allを実行することで、配布されているファイルとの違いを検出できます。ただし、これは「プラグインが改ざんされていないこと」を担保するものであって、「脆弱性のあるプラグインが配布されていた」ケースは防ぐことができません。 - セキュリティサービスを提供するPatchstackはバグハントを行っており、公式ディレクトリにあるプラグインの脆弱性を発見すると、作者に報告します。
ただ、これらはすべてプラグイン作者の対応があってはじめて効果を発揮します。もちろん対応しないということもありえます。その場合は代替プラグインを探すなどの対応が必要になるでしょう。
サードパーティープラグインの脆弱性をいちはやく検知するには、WordfenceやWPScanなどのサービスを使うのがよいでしょう。
自作コードのセキュリティを担保する方法
エンタープライズの現場ではプラグインやテーマがカスタムのものである場合も多くあります。この場合、以下のようなツールを使ってコードの安全性を担保する必要があります。
- 先述したPlugin Checkを使う。公式ディレクトリに配布予定がない場合は偽陽性(例・公式ディレクトリにだけ必要な実装がないと警告がでる)も出てしまいますが、スキャンしないよりは遥かによいです。
- 静的解析ツールを使う。PHP_CodeSnifferやPHPStanなどのツールを使うことで、コード上でセキュリティリスクがありそうな箇所を指摘してくれます。いずれもWordPressのための専用ルール(wpcs, phpstan-wordpress)が公開されています。GitHub ActionsなどのCIに組み込めば、さらに安心です。
- 依存関係チェックツールを使う。最近の開発ではcomposerやnpmなどのパッケージマネージャーを使うことが前提となっています。ここで脆弱性のあるライブラリが紛れ込んでしまうと、自作のプログラムに脆弱性が輸入されてしまいます。これはプラグインとまったく同じ構図です。GitHubのDependaBotやSnykなどのツールを利用することで、脆弱性のあるライブラリを検出してくれます。
脆弱性テストを行う
これまで紹介してきた脆弱性対策は大別すると次のようなものでした。
- 最新にする
- 信頼できるものを使う
- 脆弱性情報データベースを参照する
- 静的解析でコード上のセキュリティリスクを潰す
では、果たしてこれをやったことで万全と言えるのでしょうか? すべてが組み合わさっているWordPressサイト自体が安全であるかを確認するには、やはりそのサイトをチェックする必要があります。
もちろん、テストシナリオを用意してチェックを行うことも重要ですが、それ以外に以下のような選択肢もあります。
セキュリティスキャンをする
実際にリクエストを送って挙動を確認する層です。ZAPなどが有名ですが、セキュリティスキャナを実際のサイトに対して実行します。本番と同一構成のステージング環境に対して定期実行するのが理想ですが、受け入れテストでは「本番環境に対して実行したい」というケースもありえます。
セキュリティスキャナーは実行者に悪意がないという点以外は、クラッキングツールと同じ動作をします。したがって、関係機関への連絡が必要になることがあります。たとえば、AWSでは侵入テストに対するポリシーを公開していて、テスト可能なサービスと承認の要不要を公開しています。
コードや構成をチェックするセキュリティ対策とは異なり、動いているサイトの実際の応答を見ます。設定の抜け、想定外の経路、環境固有の問題が出てきます。
第三者による診断を受ける
外部の専門機関による診断です。Webアプリケーション診断が一般的で、自動スキャンと人間による手動検査を組み合わせて実施されます。脆弱性テストだけが含まれるわけではないですが、テスト項目にセキュリティチェックが入ることは多いです。メリットは以下の通り。
専門家が見ること。 権限を変えて試行する、業務フローの意図を読んで抜け道を探す、複数の指摘を組み合わせて実害を評価する。ここはいまのところ自動化が困難なところです。
記録が第三者名義になること。 これが最大の違いです。自社スキャンの結果は自己申告ですが、第三者診断の報告書は外部の判断として提出できます。「対策した証拠を集める」という目的において、最も強い証拠になります。エンタープライズの受け入れテストではこの報告書が検収完了の条件になることもあります。
最大の問題は費用がかかること。静的解析・ツールの更新・自社チェック・セキュリティスキャンなどを行わずに第三者診断を受けるのは費用の無駄です。自動検出できる指摘に外部の費用を払うことになります。第三者に払うお金は、機械が見つけられないものを見つけてもらうために使うべきです。
なお、第三者によるWebアプリケーションテストについては「第三者によるWordPressの品質担保|受け入れテストの種類と指摘への向き合い方」で詳しく紹介しています。
チーズの穴は動く:脆弱性の変化
第三者による報告書には「結果は診断時点のものであり将来を保証しない」という注意書きが入ります。それもそのはず、WordPressの場合、プラグインの脆弱性情報はほぼ毎週更新されるため、診断の翌週にはもう構成部品の状態が変わっているからです。スイスチーズの穴は動くのです。
したがって、手段は性質によって実施の頻度が変わります。
| 手段 | 性質 | 実施のタイミング |
|---|---|---|
| 実装作法確認・静的解析 | 継続 | コードを書くたび(CI) |
| 依存関係の照合 | 継続 | 毎日〜毎週(自動) |
| 自主スキャン | 半継続 | 週次〜月次 |
| 第三者診断 | 点 | 新規構築時、大規模改修時、年次、外部要求時 |
第三者診断が実施されるきっかけは、実務では次の3つです。
- 新規構築・リニューアルの受け入れテスト:最も多い。検収の条件として実施される
- 定期実施:年次など、セキュリティポリシーに基づく
- 外部からの要求:取引先のセキュリティ審査、監査部門からの指示
注意したいのは、1番目しか実施していない組織が多いことです。公開時点の状態は確認されたが、その後は誰も検証していないという状態は珍しくありません。これは、穴が動くという前提を無視した運用です。
費用はおおむね画面数とパラメータ数、そして手動検査の比重で決まります。全体を対象にすると膨らむため、個人情報を扱う画面、認証・認可が関わる画面、決済や外部連携、直近の改修箇所という順に優先度をつけて絞るのが実務的です。
これから求められること:証拠の機械可読化
今後の方向性についても触れておきましょう。
ここまで「対策した証拠を集める」ことがセキュリティ品質だと述べてきましたが、その証拠の形式が変わりつつあります。人間が読む報告書から、機械が処理できるデータへという流れです。
象徴的なのが SBOM(Software Bill of Materials) です。ソフトウェアの構成部品を一覧化した、いわば部品表です。米国では政府調達の要件として求められるようになり、日本でも経済産業省が導入の手引を公開しています。形式としてはSPDXやCycloneDXが使われます。
これは「適切に管理しています」という申告ではなく、構成の一覧を検証可能な形式で提出させる仕組みです。提出を受けた側は、それを脆弱性データベースと自動照合できます。
WordPressサイトにとって、これは無縁な話ではありません。プラグインとテーマの集合体であるという構造は、まさにSBOMが対象とするものです。現時点でWordPress案件にSBOMの提出が求められるケースは多くありませんが、エンタープライズの調達要件がその方向に動いていることは抑えておくべきでしょう。GDPRのように、これに対応したプラグインが出てくるかもしれません。
DependabotやWPScannerを使った依存関係の管理と似たようなものがそのままSBOM対策の資産になるかもしれません。構成の一覧は既に手元にあります。証拠を集めるプロセスを回していれば、形式が変わっても対応できるはずです。
まとめ
- 「これをやれば安全」という条件は存在しません。 すべての脆弱性を検出する手段はなく、すべての攻撃を防ぐ設定もありません
- 防御は多層に重ねたスイスチーズモデルが適切です。どの層にも穴がありますが、すべての穴が同時に並ばなければ突破されません
- チーズの穴は動きます。層は劣化し、新しい脆弱性が追加され、運用の中で設定が変わります。一度の確認では足りません
- 脆弱性対策の品質とは状態ではなく、「何を、どの手段で、いつ確認し、どう判断したか」という記録の集積です
- 手段には階層があります。実装作法、静的解析、依存関係の継続照合、シナリオテスト、自主スキャン、そして第三者による診断。それぞれ見落とすものが違います
- 第三者診断は最上位の手段です。人間の判断が入り、記録が第三者名義になるため、最も強い証拠になります。ただし下の層を整えずに受けても、費用の大半は自動検出できる指摘の対価になってしまいます
- 「問題ゼロ」を目標にしないこと。 それは検出されにくい手段を選ぶ動機になります。目標は、検出された問題に適切な判断が下され、記録されている状態です