Webサーバ(Apache)にPHP-FPMの導入による権限のセキュリティ対策

こちらの記事で紹介したように、Webサーバのコンテンツを一般ユーザの領域にしている場合、PHPなどのプログラム(動的コンテンツ)でファイルを作成したりすると、apache権限で作成してしまい、一般ユーザ領域には書き込みの権限がなく、失敗します。

この場合、ディレクトリの権限を777、つまり他人でも書き込みできる権限をディレクトリに与えれば問題は解消するように見えますが、一般公開しているディレクトリを777にすることはセキュリティ上望ましくありません。

ここでは、PHP-FPMを使用した上記問題に対する解決策を示します。具体的には、apacheユーザで書き込むのではなく、一般ユーザで書き込むように設定します。

PHP-FPMとは何をするものか

PHP-FPM(PHP FastCGI Process Manager)は、FastCGIプロトコルを使用してPHPプログラムを実行するためのプロセスマネージャです。これにより、PHPのパフォーマンスが向上し、ウェブサーバーとの連携が強化されます。以下の3点が主な機能になります。

ユーザー権限の設定: PHP-FPMでは、プールごとに異なるユーザーとグループを指定できます。これにより、異なるプールで実行されるプロセスが異なる権限を持つことが可能です。

セキュリティコンテキストの変更: PHP-FPMは、setuidとsetgidの機能を使用して、プロセスのセキュリティコンテキストを変更できます。これにより、スクリプトが実行される際の権限を制御できます。

Open Basedir設定: PHP-FPMでは、open_basedirディレクティブを使用して、PHPがアクセスできるディレクトリを制限できます。これにより、悪意あるアクセスやファイルへのアクセスを防ぐことができます。

上述のとおり、PHP-FPMにより動的なコンテンツ生成が頻繁な場合でも、セキュアで効果的な運用が可能になります。

PHP-FPMのインストール

ここでは、almalinux8系の環境で実施した内容をお伝えします。結論から、apache(webサーバ)のphpモジュールをインストールすると自動で関連付けされてインストールされます。

パッケージがインストールされているかは、以下のコマンドでご確認ください。

PHP-FPMのコンフィグ(/etc/php-fpm.d/www.conf) の設定

デフォルトのwww.confファイルは編集せずに、こちらをコピーして利用者用(ここではuser001ユーザ)のコンフィグを準備します。

変更場所は、下記になります。userやgroupには一般ユーザを指定します。

# diff www.conf.org user001.conf
4c4
< [www]
---
> [user001]
24c24
< user = apache
---
> user = user001
26c26
< group = apache
---
> group = user001
38c38
< listen = /run/php-fpm/www.sock
---
> listen = /run/php-fpm/user001.sock
325c325
< slowlog = /var/log/php-fpm/www-slow.log
---
> slowlog = /home/user001/php-fpm/log/www-slow.log
419c419
< php_admin_value[error_log] = /var/log/php-fpm/www-error.log
---
> php_admin_value[error_log] = /home/user001/php-fpm/log/www-error.log
432,433c432,433
< php_value[session.save_path]    = /var/lib/php/session
< php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache
---
> php_value[session.save_path]    = /home/user001/php-fpm/session
> php_value[soap.wsdl_cache_dir]  = /home/user001/php-fpm/wsdlcache

次に、user001ユーザのhome にphp-fpm関連(/home/user001/php-fpm と log、session、wsdlcache )ディレクトリを作成し、パーミッションを770(ただしlogディレクトリだけは750。その理由はこちらを参照)、オーナーは、user001:user001にします。設定の具体的なコマンドは以下の通りです。

最後にサービスを起動します。

apacheのコンフィグの設定

httpd.confやssl.confなどの、一般ユーザのドキュメントディレクトリを設定している部分に下記の黄色でマーカーしている部分を追記ます。

DocumentRoot /home/www/public_html

<Directory "/home/www/public_html">
 AllowOverride All
 Require all granted
 Options FollowSymLinks

 <FilesMatch \.php$>
   SetHandler "proxy:unix:/run/php-fpm/user001.sock|fcgi://localhost"
 </FilesMatch>

</Directory>

追加が終わりましたら、apacheと(念のため)php-fpmのサービスを再起動して反映させます。

動作確認のチェックポイント

以下にsockファイルができているか確認する。

PHP-FPMのログファイルにエラーを吐いていないか確認する。利用者のプロセスがあるかを php-fpm でgrepして確認する。

ファイルを作成する簡単なphp(test.php)を動かして、一般ユーザ権限で作成されるか確認する。

<?php
$file_handle = fopen( "./testfile.txt", "w");
fwrite( $file_handle, "動作テスト");
fclose($file_handle);
?>

このファイルを一般ユーザの public_html 配下に配置して、ブラウザ等でhttps://hogehoge.com/test.php にアクセスしてみます。ブラウザには何も表示されないと思いますが、public_html に testfile.txt が一般ユーザ権限で出来ていればOKです。

もし何か設定が誤っていたり、標準のapacheユーザで実行された場合は、ファイルは作成されません。

php-fpmのログローテートの設定も忘れずに

忘れがちなユーザ領域のログのローテートの設定も実施しておきます。

# more /etc/logrotate.d/php-fpm
/home/user001/php-fpm/log/*log
/var/log/php-fpm/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/kill -SIGUSR1 `cat /run/php-fpm/php-fpm.pid 2>/dev/null` 2>/dev/null || true
    endscript
}

logrotateの空動作をするオプション(-d)を付けて、実際にはローテートしませんが、エラーが出ないかどうかを確認します。

phpMyAdminなどapache権限で動作するミドルウェアがある場合は要注意

phpMyAdminなどapache権限で動作するミドルウェアがなければ特に問題ございませんが、デフォルトのwww.confの中身を変更してしまうと、うまく動かないことが判明しました。

具体的には、phpMyAdminで、こちらのとおり、phpMyAdminにrootでの利用を禁止する設定をしていたにもかかわらず、rootでログイン出来てしまいました。(もっと言うと、phpMyAdminにログイン後、temp領域にアクセス権がない、といったエラーも出ていました)

調査の結果、phpMyAdminはapache権限で動作する必要があるのに対し、上記のphp-fpmの設定で一般ユーザ権限で、phpファイルを動作させる設定になっていたため、root使用禁止部分のコンフィグ(config.inc.php)も読み込まれていないようでした。(こちらも.phpファイルです…)

ですので、このケースは、/etc/php-fpm.d/www.conf はデフォルトのまま設定変更せず、user001.confといった別のファイルを必ず作成し、そちらを利用者用に設定しましょう。

今回はここまでです。最後までお読みいただきありがとうございました。