マルチサイトの個々のブログ内で設定するtheme内で他ユーザーのデータを取得することができる
標準のマルチサイトでは独自のテーマをインストールすることはできない
wordpressのマルチサイト構成ではユーザーが任意にブログを開設することができる。
標準のマルチサイト環境は、プラグインやテーマを特権管理者のみが新規にインストールできる仕様になっているので、マルチサイト構成に問題があるわけではない。本ブログでは、wordpressのマルチサイト構成を利用して、ブログを開設したユーザーにテーマのインストールを委任する方向で検討しているためその点を前提としている。具体的には、
- administratorにsuper admin権限を一時付与
- ネットワーク管理画面からテーマのインストール・編集を可能とする
以前のエントリーでも書いたが、wpmuで上のことをやろうとすると開発工数は増加する。そして、各ブログのユーザーが任意のテーマをインストールできるようにすると、wordpressのデータベースのグローバルテーブルに対するアクセス制御が必要になってくる。
theme内でget_userdataを実行してみる
マルチサイト構成のwordpressで以下のPHPコードを追記すると、ユーザー情報を取得することができる。
$user_info = get_userdata(3); var_dump($user_info);
get_userdataに渡す引数(user_id)は3にしてあるが、このidは1から順番にふられていくものなので、4とか5とか任意の番号を渡せばそのユーザーのデータを取得することが可能である。これは、他ユーザーのユーザー情報をテーマ内で取得することができるということになり、不特定多数のユーザーが利用するwebサービスの場合には何かしらの対策が必要と考えている。
具体的には、wordpressのデータベース寄りの部分でグローバルテーブルへのアクセスを制御することで、各ブログからの他ユーザーに関するデータへのアクセスをコントロールする方法があげられる。
グローバルテーブルへのアクセス制御
get_userdataは内部でキャッシュしているのでデバッグ時は注意に書いてみたのだが、
wp_users
wp_usermeta
が該当し、リンク先のエントリーでは、query filter hookを利用してグローバルテーブルに対するSQLを制御している。この方法では、query発行前に該当するSQL文をカスタマイズしている。同じ効果を得る方法として、
[WordPress] カスタマイズした wpdb クラスを使用する方法
があり、wordpress3.8で以下のようにdb.phpを作成し、tables function内でグローバルテーブルに対するアクセスを構成する変数を無効にすることでユーザーデータの取得を制御することができる。
switch ( $scope ) { case 'all' : $tables = array(); if ( is_multisite() ) $tables = array(); break; case 'blog' : $tables = $this->tables; break; case 'global' : $tables = array(); if ( is_multisite() ) $tables = array(); break; case 'ms_global' : $tables = array(); break; case 'old' : $tables = array(); break; default : return array(); break; }
上の例は、
wp-includes/wp-db.php
のtables functionをオーバーライドしてグローバルテーブルに対するクエリの場合はtables変数を空にしている。
wp_cacheの制御
get_userdataでは、内部でキャッシュを行っている。そのためデータベースに送られるqueryを操作してもキャッシュが残っていればユーザー情報をテーマ内で取得可能になってしまう。そのため、データベースのグローバルテーブルに対するSQLの制御だけでなく、wp_cacheに関するキャッシュデータの制御も必要になってくる。
しかし、残念なことにwp_cacheに関するカスタマイズをwordpressのactionやfilterのフックで操作する方法については現在までのところ見つけることができていない。おそらくwordpress3.8の時点では、wp_cacheに関するhookは用意されていないと判断している。そのため一部コアファイルを操作することで、ユーザーデータのキャッシュを制御することにした。
get_userdataは、
wp-includes/plugable.php
に記述されている。そして、内部でget_data_byを呼び出しており、その関数は、
wp-includes/capabilities.php
に記述されている。get_data_by関数の内部で、
update_user_caches( $user );
という関数が実行されるようになっており、その関数の内部でwp_cache系の操作が行われている。具体的には、
wp-includes/user.php
にupdate_user_cachesは書かれている。また、
wp-includes/cache.php
にwp_cacheのオブジェクトキャッシュを操作する一連の関数が記述されている。
get_userdataに関しては、上に書いたupdate_user_cachesの部分をコメントアウトすることでユーザーデータのキャッシュを防ぐことができる。
queryやglobal tablesの制御とwp_cacheの制御を行うことで、wordpressのマルチサイト構成で他のブログユーザーの情報にアクセスすることを防ぐことはできる。
参考