WordPressをヘッドレス化する時に気になるセキュリティ問題
WordPressをヘッドレスCMSとして構築して、バックエンドとフロントエンドを分離するケースを考えてみます。そもそもWordPressには標準でREST APIが付いているので、CMSの構築自体にそこまでの手間はかかりません。
さて、分離するメリットはいくつかありますが、その一つにセキュリティリスクの軽減が挙げられます。WordPressは、広く使われているだけあって(プラグインも含む)脆弱性報告が多く、改ざん被害も過去多数報告されています。
そこで、バックエンドを全て隠蔽してしまい、攻撃者がそもそも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に書き換わります。
帯域の負荷も減らすことができるので、重たいファイルを多数扱う場合はおすすめです。
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の設定をします。
<VirtualHost *:80>
ServerName files.example.com
DocumentRoot /path/to/wp/wp-content/uploads
</VirtualHost>
あとはApacheを再起動すれば、無事アップロードされたメディアをfiles.example.comで参照できるようになります。
2-3. WordPressで扱うメディアのURLを変更する
このままでは、Wordpressの管理するメディアのURLはデフォルトのままです。変更するために、以下のようなフックを追加すれば完了です。
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