🔥

WordPressをヘッドレス化する時に気になるセキュリティ問題

3 min read

WordPressをヘッドレスCMSとして構築して、バックエンドとフロントエンドを分離するケースを考えてみます。そもそもWordPressには標準でREST APIが付いているので、CMSの構築自体にそこまでの手間はかかりません。

さて、分離するメリットはいくつかありますが、その一つにセキュリティリスクの軽減が挙げられます。WordPressは、広く使われているだけあって(プラグインも含む)脆弱性報告が多く、改ざん被害も過去多数報告されています。

https://saas.gmocloud.com/service/websecurity/threat/cyberStory.html

そこで、バックエンドを全て隠蔽してしまい、攻撃者がそもそもWordPressにたどり着けないようにすれば、攻撃自体を未然に防ぐことができます。

バックエンドの隠蔽

フロントからAjaxで直接バックエンドに接続してしまえば、WordPressの場所はバレてしまうため、隠蔽するには以下のように工夫する必要があります。

  • 静的サイトジェネレータを使う
  • サーバサイドでJSONを取得する
  • WP REST APIから情報を取得して返すAPIを作る(Proxyのようなもの)

しかし、どういった手法を取っても1つ別の問題が残ってしまいます。それは、画像などのメディアファイルが、バックエンドのドメインがついたURLで渡されてしまうことです。これではWordPressのインストールされているホストがバレバレです。

こんな感じ。
https://backend.example.com/wp/wp-content/uploads/2021/07/30/image.png

ちなみに、Next.jsのnext/imageを使っても、特殊なloaderを作らないとURLに含まれるかたちになるかと思います。

メディアのURL

上記の問題の解決策として思い浮かぶものを、いくつか挙げます。

  • フロントにメディアを全て同期する
  • フロントでメディアを取得・キャッシュする
  • メディアを別ホストで配信する

上2つは、なんと言うか楽してWordPressにしてるのにこんなことするのは面倒くさい、という感じですね。システムが確立してしまえば、完全な切り離しができるので安泰ですが。

ということで、3つめのメディアを別ホストで配信する方法を2つ考えてみます。

1. Amazon S3の静的ホスティングを使う

簡単にできるプラグインが存在します。S3のバケットを用意して、プラグインの設置と設定を行えば、メディアの保存先も配信されるURLもS3に書き換わります。

https://hacknote.jp/archives/43897/

帯域の負荷も減らすことができるので、重たいファイルを多数扱う場合はおすすめです。

2. メディア配信用のドメイン(サブドメイン)を用意する

https://backend.example.com/wp/wp-content/uploads/2021/07/30/image.png
となっているURLを、
https://files.example.com/2021/07/30/image.png
に変更することを目的とします。

詳しくみていきましょう。

2-1. ドメインの用意

以下で考えてみます。

ドメイン
バックエンドサーバ backend.example.com
メディア配信サーバ files.example.com
フロントエンドサーバ example.com

バックエンド、フロントエンドはドメインのAレコードが登録されており、閲覧できる状態にあるとします。この時、メディア配信用のドメインも、バックエンドのIPアドレスに向けることで、メディアファイルを参照する仕組みを作ることができます。

2-2. ドキュメントルートの設定(Apache想定)

サーバ側では、files.example.comを受け入れるためのVirtualHostの設定、DocumentRootの設定をします。

httpd.conf
<VirtualHost *:80>
  ServerName files.example.com
  DocumentRoot /path/to/wp/wp-content/uploads
</VirtualHost>

あとはApacheを再起動すれば、無事アップロードされたメディアをfiles.example.comで参照できるようになります。

2-3. WordPressで扱うメディアのURLを変更する

このままでは、Wordpressの管理するメディアのURLはデフォルトのままです。変更するために、以下のようなフックを追加すれば完了です。

functions.php
add_filter("wp_get_attachment_url", function($url, $post_id){
  $path = preg_replace("@^http.+uploads/(.+?)$@", '$1', $url);
  return "https://files.example.com/{$path}";
}, 10, 2);

2つめの方法では、バックエンドとフロントエンドは分離しましたが、バックエンドと同じサーバ内でメディアを配信しています。もっとセキュリティを高めたい場合や負荷対策が必要な場合は、前述した方法でS3を利用する、ファイルを同期させるなど、他にも検討の余地はありそうです。ブロックストレージやDockerのボリュームを使っても、切り離すことはできそうですね。

他のCMSにはあまり詳しく無いですが、同じような仕組みで動いているものは、同じような方法でヘッドレスに対応できそうです。参考になれば幸いです。

Discussion

ログインするとコメントできます