suEXECでphpを動かせばユーザー毎にファイルの権限がきっちり別れます.
つまり、PHPの設定で,『Apcheから書き込みできること』などと*1な設定指南書を納品されたのでかっとなって調べた.PHPが作ったファイルがwww-dataになって大慌てしなくて済みます
サーバーを複数人で使うのに結構大事な設定だったりしますphp-cgi
php のCGIモードを有効にする
ユーザーディレクトリ userdir で実行するときは mod_php でなく suexec のPHP-cgiを使うとファイルのパーミッションやセッションを読まれたりすることが無くなる.php.iniのsafe-modeは非推奨になったみたいなので各自のuserdir で実行出来るPHP環境を作りたい
全体の流れはこんな感じ
sudo aptitude install php5-cgi sudo a2dismod php5 #モジュール版はとりあえずOFF(併存できるけどね sudo aptitude install apache2-suexec-custom sudo a2enmod actions #php5のCGIは force-cgi-redirect の制約がある sudo a2enmod suexec sudo a2enmod userdir
モジュールが3つ一気に有効になるので、振り回されずに一つずつ解決していく
index.php
#!/usr/lib/cgi-bin/php phpinfo();
Apacheのエラーメッセージは次のような感じ
[Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] <b>Security Alert!</b> The PHP CGI cannot be accessed directly. [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] <p>This PHP CGI binary was compiled with force-cgi-redirect enabled. This [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] means that a page will only be served up if the REDIRECT_STATUS CGI variable is [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] set, e.g. via an Apache Action directive.</p> [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] <p>For more information as to <i>why</i> this behaviour exists, see the <a href="http://php.net/security.cgi-b> [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] <p>For more information about changing this behaviour or re-enabling this webserver, [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] consult the installation file that came with this distribution, or visit [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] <a href="http://php.net/install.windows">the manual page</a>.</p> [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] Premature end of script headers: index.cgi [Mon Aug 08 15:05:38 2011] [error] [client 192.168.22.195] File does not exist: /var/www/favicon.ico, referer: http://192.168.22.210/users/takuya/index.cgi [Mon Aug 08 15:22:54 2011] [notice] Graceful restart requested, doing restart apache2: Could not reliably determine the server's fully qualifi
そしてphp-cgiがuserdirで動くようにする
/etc/php.ini
; cgi.force_redirect is necessary to provide security running PHP as a CGI under ; most web servers. Left undefined, PHP turns this on by default. You can ; turn it off here AT YOUR OWN RISK ; **You CAN safely turn this off for IIS, in fact, you MUST.** ; http://php.net/cgi.force-redirect cgi.force_redirect = 0 ; The directory under which PHP opens the script using /~username used only ; if nonempty. ; http://php.net/user-dir user_dir =
拡張子php が cgi php になるように
<Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch Includes ExecCGI Action php-script /cgi-bin/php AddHandler php-script .php .cgi
cgi-binはこういう形で有効になっている
sites-enabled/000-default (centosの場合のhttpd.conf)
15 16 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ 17 <Directory "/usr/lib/cgi-bin"> 18 AllowOverride None 19 Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch 20 Order allow,deny 21 Allow from all 22 </Directory> 23
/usr/lib/cgi-bin/php とCGIを設置して,http://localhost/cgi-bin/ 経由で起動したらExecCGIをするよって事.
cgi-binで指定したアプリケーションだけを動かすようにする.
takuya@debian00:/etc/apache2$ ls -alt /usr/lib/cgi-bin/ 合計 7372 drwxr-xr-x 2 root root 4096 2011-08-08 14:14 . lrwxrwxrwx 1 root root 29 2011-08-08 14:14 php -> /etc/alternatives/php-cgi-bin drwxr-xr-x 196 root root 73728 2011-08-08 14:14 .. lrwxrwxrwx 1 root root 36 2011-08-08 12:12 apt-cacher -> ../../share/apt-cacher/apt-cacher.pl -rwxr-xr-x 1 root root 7451532 2011-03-19 02:59 php5
さらにphp-cgi のエイリアスの先をたどる
takuya@debian00:/etc/apache2$ ls -alt /etc/alternatives/php-cgi-bin lrwxrwxrwx 1 root root 21 2011-08-08 14:14 /etc/alternatives/php-cgi-bin -> /usr/lib/cgi-bin/php5
suExecの設定.
次にSuEXECを有効にする.
suexec のエラーメッセージは次のよう感じ
[Mon Aug 08 15:37:35 2011] [notice] suEXEC mechanism enabled (wrapper: /usr/lib/apache2/suexec) [Mon Aug 08 15:37:35 2011] [notice] Apache/2.2.16 (Debian) configured -- resuming normal operations
suexecの場所の確認
takuya@debian00:/etc/apache2$ ls -alt /usr/lib/apache2/suexec -rwsr-xr-- 1 root www-data 13872 2011-03-23 05:57 /usr/lib/apache2/suexec
suexecは(CGIの)実行ユーザーを切替える専用コマンドしてインストールされています.
suexecの設定を確認する.
suexecはコンパイル時にオプションとして、引数を和つぃていて,細かい設定はハードコーディング
takuya@debian00:/etc/apache2$ sudo /usr/lib/apache2/suexec -V -D AP_DOC_ROOT="/var/www" -D AP_GID_MIN=100 -D AP_HTTPD_USER="www-data" -D AP_LOG_EXEC="/var/log/apache2/suexec.log" -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" -D AP_UID_MIN=100 -D AP_USERDIR_SUFFIX="public_html"
設定は変えられない.設定変えるにはビルドが必要.でも面倒なので・・・
設定を変えられるバイナリが用意してある.
sudo aptitude install apache2-suexec-custom
設定変更可能なSuEXECバイナリのデフォルト設定
takuya@debian00:~$ sudo /usr/lib/apache2/suexec -V -D SUEXEC_CONFIG_DIR=/etc/apache2/suexec/ -D AP_GID_MIN=100 -D AP_LOG_EXEC="/var/log/apache2/suexec.log" -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" -D AP_UID_MIN=100
設定は/etc/apache2/suexec/でカスタマイズ可能
たとえば
- /home/%u/public_html/
- /home/%u/www
に換えたいときなどに重宝する.
クセはあるが設定はこんな感じ
/home/ public_html # The first two lines contain the suexec document root and the suexec userdir # 最初の2行は必ずUserDirで、SuEXECするディレクトリとその上位ディレクトリ # suffix. If one of them is disabled by prepending a # character, suexec will # refuse the corresponding type of request. # This config file is only used by the apache2-suexec-custom package. See the # suexec man page included in the package for more details. #..略 SuexecUserGroup takuya hdusers
SuexecUserGroup 設定はVirtualhostやメインサイトなど /home/ 以外の場所で有効.
だれがプロセスを起動しているか不明になるので必要になる.(Virtualhostやメイン設定だと www-data でイイと思うけどね)
できあがった設定
<IfModule mod_userdir.c> UserDir public_html UserDir disabled root <Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch Includes ExecCGI AddHandler cgi-script .cgi </Directory> <Directory /home/*/public_html/cgi-bin/> AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch Includes ExecCGI SetHandler cgi-script </Directory> <Directory /home/takuya/public_html > AddHandler php-script .php Action php-script /~takuya/cgi-bin/php </Directory> </IfModule>
テストしてみる
#!/usr/bin/env php-cgi <?php var_dump(posix_getpwuid(posix_getuid()));
結果
array(7) { ["name"]=> string(6) "takuya" ["passwd"]=> string(1) "x" ["uid"]=> int(1000) ["gid"]=> int(1000) ["gecos"]=> string(10) "here,i am " ["dir"]=> string(12) "/home/takuya" ["shell"]=> string(9) "/bin/bash" }
ちゃんとTakuyaさんになってます
perlも実験
1 #!/usr/bin/env perl 2 3 print "Content-type: text/plain\n\n"; 4 printf "user = %s\n",(getpwuid($>))[0]; 5 exit;
結果
DOCUMENT_ROOT="/var/www" GATEWAY_INTERFACE="CGI/1.1" HTTP_ACCEPT="text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1" HTTP_ACCEPT_ENCODING="gzip, deflate" HTTP_ACCEPT_LANGUAGE="en,ja-JP;q=0.9" HTTP_CONNECTION="Keep-Alive" HTTP_HOST="192.168.9.21" HTTP_USER_AGENT="Opera/9.80 (Windows NT 6.1; U; ja) Presto/2.9.168 Version/11.50" PATH="/usr/local/bin:/usr/bin:/bin" QUERY_STRING="" REMOTE_ADDR="xxx.xxx.xxx.xxx" REMOTE_PORT="3779" REQUEST_METHOD="GET" REQUEST_URI="/~takuya/printenv.cgi" SCRIPT_FILENAME="/home/takuya/public_html/printenv.cgi" SCRIPT_NAME="/~takuya/printenv.cgi" SERVER_ADDR="192.168.9.21" SERVER_ADMIN="webmaster@localhost" SERVER_NAME="192.168.9.21" SERVER_PORT="80" SERVER_PROTOCOL="HTTP/1.1" SERVER_SIGNATURE="<address>Apache/2.2.16 (Debian) Server at 192.168.9.21 Port 80</address>\n" SERVER_SOFTWARE="Apache/2.2.16 (Debian)"
CGIとしてもちゃんと動いてます.
cgiの動作原理について
http://localhot/~takuya/test.cgi
を起動したら
AddHandler cgi-script .cgi
が反応して,プログラムを実行する。一行目の
#!/usr/bin/env php-cgi
拡張子PHPはどうしようか
このままだと sheban #!/usr/bin/env php-cgi が必須だし拡張子cgi必須だし。拡張子PHPにしたい
設定書いてみた
AddHandler php-script .php Action php-script /cgi-bin/php
実行してみた
setuid 効いてないじゃん!ってそりゃそうだ
CGIファイルのオーナにSuExecするから php のオーナーは root だから SuexecUserGroupで指定した www-data になります.
cgi の動作原理について
cgi は Apacheが起動する
ttp://takuya.eample.jp/sample.php
は handler が起動して
ttp://takuya.eample.jp/cgi-bin/php.exe?/home/takuya/public_html/sample.php
のように cgi-bin は引数にファイル名を取ることが出来る.内部的に自動変換がされている
cgi ファイルは shebang を利用している。実行可能
shebang を起動するときに SuEXEC は setuid する
- cgi ファイルはActionを決めることが出来る
- 該当拡張子が来たらファイル実行する代わりにActionに渡す。
- SuEXECはAction指定先を確認する。←ここがActionでSuEXECが効かない原因と思われる
php のオーナーが www-data です
ではどうするのか
ユーザー単位で、CGIディレクトリを作る
調べてみたら、ロリポップはユーザー毎に phpを cgi-bin に置いてあるみたい
なるほどね。そうすれば、ユーザー毎にphp.ini使えるもんね
How and why Anchor runs PHP as CGI with suexec on their shared hosting servers - Web and dedicated hosting tutorials by Anchor
Many apache configurations will already have something like this. ScriptAlias is used to map the /cgi-bin/ path to a specific directory, and mark the contents as executable.
ScriptAlias /cgi-bin/ /var/www/users/username/cgi-bin/
そもそも何でsuexecでPHPを動かすのか
リソース制限
- RLimitCPU - Limit the CPU consumption of a process to N seconds
- RLimitMEM - Limit the memory consumption of a process to N bytes
- RLimitNPROC - Limit the number of processes that can be launched to N
suexecならリソース制限がかけやすい(らしい
ちなみに cgi-binにリンクを置くとどうなるのか
drwxr-xr-x 2 takuya takuya 4096 2011-09-03 08:43 . lrwxrwxrwx 1 takuya takuya 20 2011-09-03 08:43 php -> /usr/lib/cgi-bin/php drwxr-xr-x 6 takuya takuya 4096 2011-09-03 08:43 ..
結果
Forbidden You don't have permission to access /~takuya/cgi-bin/php/~takuya/info.php on this server. Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request.
なぜか
AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch Includes ExecCGI
SymLinksIfOwnerMatch に引っかかって実行出来ない
2014-05-22 追記
Actionディレクティブが動かなかった。
Invalid command 'Action', perhaps misspelled or defined by a module not included in the server configuration
原因は、a2enmod actionsを忘れてた。
*1:書いたヤツは何も考えてない