複数の WordPress を共用サーバーでホストするリスクを軽減する
動作環境
- Conoha で配っている kusanagi ディストリビューション(CentOS7)を使用
- hhvm + apache は同一サーバーに配置
- 同一サーバーで WordPress 他 5 サイトが稼働しています
- http://jpvlad.com (geeklog)
- http://beautyonsa.com (WordPress)
- http://japan-onsa.org (WordPress)
- http://tft-japan.com (WordPress)
- http://heartbeat.selfnavi.com (内向け、php)
概要
hhvm の機能で共用サーバーの複数サイトの WordPress(または PHP のフレームワーク)でお互いのディレクトリを見えなくします。 URL 毎に vsftp の chroot のような設定をする感じ。
共用サーバーで複数サイトを動かすことのリスク
kusanagi を入れれば非力のサーバーでも WordPress がそれなりの速さが出るようになる。同じサーバーでもういっちょサイト作ってみようかとなるわけです。しかし同一サーバーだとどれか一つでも WordPress の脆弱性を抱えているとそこを起点としてパッチがきちんと当たっている他のサイトも書き換えが可能なわけです。apache とか nginx は単一ユーザーで動かしていますからね。
WordPress の安全性を高める でも触れられています。
サーバーの脆弱性 共用サーバー (同じサーバー上に他の人のサイトがホスティングされている環境) で誰かのサイトが感染すると、たとえこのガイドに従っていた場合でもあなたのサイトも感染してしまう可能性があります。使用している[用語集#Hosting_provider Web ホスト] がどのようなセキュリティ対策を行っているか確かめておいてください。
hhvm の設定で共用サイトのリスクを低減する
共用サーバーで誰かのサイトから影響を受けないようにするためには、よくある答えはそもそも別のサーバーにしろ(AWS あるし)、なのですが、低コスト運用を目指したいのにサーバーの乱立は避けたいところです。そこで、hhvm が持っている vsftp でいう chroot のような機能を使い、サイトをまたいでファイルが見えないようにします(ただし下記で実験しますが OS コマンドインジェクションには効果がありません )。
今回の例での 5 つのサイトについて、サイト毎にどこのディレクトリで動いているかを /etc/hhvm/php.ini
に 足します:
hhvm.server.safe_file_access = true
hhvm.server.allowed_directories[] = /usr/share/pear
hhvm.server.allowed_directories[] = /tmp
hhvm.server.allowed_directories[] = /usr/bin
hhvm.virtual_host[jpvlad][prefix] = jpvlad.com
hhvm.virtual_host[jpvlad][overwrite][server][allowed_directories][] = /var/www/jpvlad/geeklog
hhvm.virtual_host[tft][prefix] = tft-japan.com
hhvm.virtual_host[tft][overwrite][server][allowed_directories][] = /home/kusanagi/tftjapan/DocumentRoot
hhvm.virtual_host[onsa][prefix] = japan-onsa.org
hhvm.virtual_host[onsa][overwrite][server][allowed_directories][] = /home/kusanagi/japan-onsa/DocumentRoot
hhvm.virtual_host[beauty][prefix] = beautyonsa.com
hhvm.virtual_host[beauty][overwrite][server][allowed_directories][] = /home/kusanagi/beautyonsa/DocumentRoot
hhvm.virtual_host[heartbeat][prefix] = heartbeat.selfnavi.com
hhvm.virtual_host[heartbeat][overwrite][server][allowed_directories][] = /home/kusanagi/heartbeat/DocumentRoot
足し終わったら:
# service hhvm restart
説明です
-
最初の
hhvm.server.safe_file_access = true
true でないと、chroot のような機能は動きません。忘れないようにします。
1. 次に、全サイト共用のディレクトリを設定します。
```
hhvm.server.allowed_directories[] = 共用ディレクトリ名
-
共用ディレクトリの設定の後は各サイト毎設定です。ここでは http(s)://beautyonsa.com については hhvm 内の名前を
beauty
としています。ご自身の現状とあわせ自由に設定してください。
hhvm.virtual_host[beauty][prefix] = beautyonsa.com
1. 次に `beauty` がどこのディレクトリを使うのかを指定します。複数あるときは `hhvm.virtual_host[beauty][overwrite][server][allowed_directories][] = ` の行を足してきます。
```
hhvm.virtual_host[beauty][overwrite][server][allowed_directories][] = /home/kusanagi/beautyonsa/DocumentRoot
- (hhvm のリスタート後)http(s)://beautyonsa.com アクセス時は
/usr/share/pear
,/tmp
,/usr/bin
,/home/kusanagi/beautyonsa/DocumentRoot
以外の PHP プログラムを実行しようとしても全部 404 (not found) 扱いとなります。 - 3, 4 を繰り返しホストしてるサイト分ほど加えます。 hhvm 内の名前は変更してください。
サイト毎で設定できるのはディレクトリだけではないです。設定できる項目は This is an example of the ini format for hhvm.virtual_hosts をご覧ください。
auto_prepend_file
の扱い
PHP では、php.ini
の
auto_prepend_file =
で PHP 実行毎フックをいれることができます。私の場合ですと php.ini
のmemory_limit
設定に目星をつけるために auto_prepend_file
の PHP プログラムで一定以上のメモリーを食う PHP ファイル名をログにだすようにしています(hook.php
)。こういうときも共用ディレクトリとして auto_prepend_file =
のディレクトリを加えておかないとなりません、例えば、次のように共用ディレクトリ扱いとします( 実行毎フックがなければ追加の必要はありません ):
auto_prepend_file = /home/kusanagi/auto_prepend/hook.php
hhvm.server.allowed_directories[] = /home/kusanagi/auto_prepend
すっかり忘れていると 404 エラーで嵌ることになります。
hhvm.server.safe_file_access = true
でどこまで chroot のような効果を出せるのか
hhvm の生死判定をするサイト heartbeat.selfnavi.com でテストしてみます(作り方は 生死判定をするサイトの設置 を参照)。hhvm の設定と共用している各サイトのディレクトリ構成は /etc/hhvm/php.ini
にあります。共用サーバーの別のサイトのファイルにアクセスできるかどうか調べるために test.php
を置きます。
<?php
print "*** cat ***\n";
system('/bin/cat /home/kusanagi/beautyonsa/DocumentRoot/index.php', $result);
print "*** fopen ***\n";
$fp = fopen("/home/kusanagi/beautyonsa/DocumentRoot/index.php", "r");
if (!($fp === false)) {
while( ! feof( $fp ) ) {
echo fgets( $fp, 9182 );
}
fclose($fp);
}
次の行で、unix のコマンドから共用サーバーの別のサイトにアクセスできるかどうかを調べます:
system('/bin/cat /home/kusanagi/beautyonsa/DocumentRoot/index.php', $result);
次の行で、php で共用サーバーの別のサイトにアクセスできるかどうかを調べます:
$fp = fopen("/home/kusanagi/beautyonsa/DocumentRoot/index.php", "r");
hhvm.server.safe_file_access = false
で動かしてみます
-
cat
,fopen
とも成功します。普通の動きです
$ wget -qO- http://heartbeat.selfnavi.com/test.php
*** cat ***
<?php
/**
* Front to the WordPress application. This file doesn't do anything, but loads
* wp-blog-header.php which does and tells WordPress to load the theme.
*
* @package WordPress
*/
/**
* Tells WordPress to load the WordPress theme and output it.
*
* @var bool
*/
define('WP_USE_THEMES', true);
/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );
*** fopen ***
<?php
/**
* Front to the WordPress application. This file doesn't do anything, but loads
* wp-blog-header.php which does and tells WordPress to load the theme.
*
* @package WordPress
*/
/**
* Tells WordPress to load the WordPress theme and output it.
*
* @var bool
*/
define('WP_USE_THEMES', true);
/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );
hhvm.server.safe_file_access = true
で動かしてみます
-
cat
コマンドは成功します、つまり OS コマンドインジェクションには効果がありません -
fopen
は失敗します
wget -qO- http://heartbeat.selfnavi.com/test.php
*** cat ***
<?php
/**
* Front to the WordPress application. This file doesn't do anything, but loads
* wp-blog-header.php which does and tells WordPress to load the theme.
*
* @package WordPress
*/
/**
* Tells WordPress to load the WordPress theme and output it.
*
* @var bool
*/
define('WP_USE_THEMES', true);
/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );
*** fopen ***