delete from hateblo.jp where 1=1;

タイトルに意味はありません。

Apache2におけるマルチユーザー環境(php-cgi+fcgid+suexecで権限分離編)

対象

  • Debian lenny
  • Apache2
  • シングルホストで複数ドメインを複数人で運営する

Debianのシステムは標準設定で十分使いやすくなっているので、さほど設定する必要はない。

動作イメージ

各ユーザーはそれぞれのLinuxユーザー権限でスクリプトを実行できるようにする。

クライアント | apache権限                | 利用者権限
Request     -> Apache -> fcgid -> suexec -> ラッパー -> php-cgi -> *.php
Request     -> Apache -> suexec+mod_perl ->                        *.pl,*.cgi 
検討時のメモ
  • いい所
    • phpバージョンを切り替えることが出来る(ラッパーの書き換えだけで済む)
    • ユーザー権限で動作させることができる
  • suPhpを使わないのか
    • 動作が鈍くなる(そんなに変わらないかもしれない)
    • 設定が煩雑になる傾向にある
  • 設定的問題
    • ラッパーをユーザーが増えるごとに設定しないといけない
    • VirtualHost内にユーザー名を複数回書かなくてはならない
  • 動作的問題
    • 動作はやはり遅い(cgiモードでの動作のため)

基本

各種インストール
sudo aptitude install apache2-mpm-worker
/etc/apache2/apache2.conf
KeepAliveTimeout 2

標準では15秒。2秒にする理由はアクセス数が多い場合、すぐにMaxKeepAliveRequestsに達してしまうから。
また、たくさんのコネクションを維持されると、すぐに上限になってしまうため。

/etc/apache2/conf.d/security
ServerTokens Prod
ServerSignature Off
TraceEnable Off

サーバー情報は極力隠すようにする。



ユーザー権限動作のための設定

各種インストール
sudo aptitude install php5-cgi
sudo aptitude install libapache2-mod-fcgid
sudo aptitude install libapache2-suexec-custom
sudo aptitude install libapache2-mod-vhost-hash-alias
sudo a2dismod php5
sudo a2dismod proxy
sudo a2dismod proxy_connect
sudo a2enmod rewrite
sudo a2enmod suexec
sudo a2enmod include
sudo a2enmod fcgid
sudo a2enmod vhost_alias

phpcgiモードで実行する。

/etc/apache2/suexec/www-data
/home
public_html

必ず、先頭2行を上記のようにしてください。
設定内容は、1行目が実行ファイルが必ず指定したディレクトリより下にある
2行目が公開パスに絶対含まれる文字列を記入する
イメージとしては、/home/*/public_html/*/*.cgiとなる。
DocumentRootには必ず1行目と2行目が含まれていなくてはならない
ちなみに、この設定はlibapache2-suexec-customのみで有効。
他のsuexec(libapache2-suexec)はコンパイル時に決めうちになっている。

/etc/apache2/mods-available/fcgid.conf
<IfModule mod_fcgid.c>
#  FCGIWrapper /usr/bin/php-cgi .php
#  FCGIWrapper /home/util/bin/php-cgi .php
#  FCGIWrapper /usr/bin/perl .pl
#  FCGIWrapper /usr/bin/perl .cgi
  PHP_Fix_Pathinfo_Enable 1
  AddHandler    fcgid-script .php
  AddType application/x-httpd-php .php
  IPCConnectTimeout 20
  MaxProcessCount 3
  DefaultMaxClassProcessCount 2
  TerminationScore 10
  SpawnScore 80
  IdleTimeout 300
</IfModule>

perlについては、mod_perlで実行する。
FCGIWapper経由だと、ラッパーが必要になってしまうため。
PHP_Fix_Pathinfo_Enable については、環境変数PATH_INFOを維持するためらしい。

/etc/php5/cgi/php.ini

fcgidのための設定を行う

cgi.fix_pathinfo=1


標準では128MBまで消費してもいいことになっているが、サーバーメモリが512しかないので、我慢の限界を念のため低くしておく。

memory_limit = 64M      ; Maximum amount of memory a script may consume (64MB)

セキュリティ的パラメータを調整

allow_call_time_pass_reference = Off
expose_php = Off
error_reporting  =  E_ALL | E_STRICT
display_errors = Off
register_long_arrays = Off
register_argc_argv = Off
magic_quotes_gpc = Off
file_uploads = Off
session.gc_divisor     = 1000
session.bug_compat_42 = 0
session.hash_function = 1
max_execution_time = 30 ; add 20120212 from atIT

セキュリティのためのパラメータの調整を行ったとき、エラーログが何処にも表示されないため、ログに吐いてあげるようにする。

log_errors = On
error_log = php_error_logs

ユーザーの作成

VirtualHostのためのLinuxのユーザーとグループを作る

uidとgidの最小値を確認する

suexecのコンパイルオプションを参照する

sudo /usr/lib/apache2/suexec -V

AP_GID_MINとAP_UID_MINの値を確認する。
デフォルトでは100となるはず。

グループを追加する
sudo addgroup --gid 500 webusers

先ほど調べた値よりも大きくなるようにgidを設定する

ユーザーを追加する
sudo adduser web1 --gid 500 --disabled-login

作ったgidを指定する

公開ディレクトリを作成する
sudo -u web1 mkdir /home/web1/public_html
ラッパースクリプトを作成する
sudo -u web1 mkdir /home/web1/bin
sudo -u web1 vi /home/web1/bin/php-cgi

以下の内容を「/home/web1/bin/php-cgi」に記述する。

#!/bin/sh 
# Wrapper for PHP-fcgi 
# This wrapper can be used to define settings before launching the PHP-fcgi binary. 

# Define the path to php.ini. This defaults to /etc/phpX/cgi. 
# export PHPRC=/home/web1/conf 

# Define the number of PHP child processes that will be launched. 
# This is low to control memory usage on a server that might launch 
# these processes for lots of domains. 
# Leave undefined to let PHP decide. 
export PHP_FCGI_CHILDREN=1 

# Maximum requests before a process is stopped and a new one is launched 
export PHP_FCGI_MAX_REQUESTS=5000 

# Launch the PHP CGI binary 
# This can be any other version of PHP which is compiled with FCGI support. 
exec /usr/bin/php5-cgi 

上記内容で保存して、実行権限を与える

sudo -u web1 chmod u+x /home/web1/bin/php-cgi

VirtualHostの設定を行う

/etc/apache2/sites-available/web1
<VirtualHost *:80>
        ServerName example.com
        ServerAlias *.example.com
        ServerAdmin webmaster@example.com
        SuexecUserGroup web1 webusers
        VirtualDocumentRoot /home/web1/public_html/%0.0
        DocumentRoot /home/web1/public_html
       <Directory /home/web1/public_html>
               Options +ExecCGI -Indexes FollowSymLinks -MultiViews
               AllowOverride All
       </Directory>
       <IfModule mod_fcgid.c>
               FCGIWrapper /home/web1/bin/php-cgi .php
       </IfModule>
       # Possible values include: debug, info, notice, warn, error, crit, alert, emerg.
       LogLevel warn
       ErrorLog /var/log/apache2/error.log
       CustomLog /var/log/apache2/access.log vhost_combined
</VirtualHost>

ドメインが追加された場合は、以下のように追記する

ServerAlias example2.com
ServerAlias *.example2.com

他のユーザーが勝手にvhostを名乗ってしまうのはまずいために、暫定的にそのようにしている。
本来なら、mod-mysql-vhostとかしてあげるのがいいのだが...パッケージがないため断念。


参考文献

改変履歴

  • 2012/02/12 phpのセキュリティ対策の追記