《PHP教程:PHP-FPM之Chroot執行環境詳解》要點:
本文介紹了PHP教程:PHP-FPM之Chroot執行環境詳解,希望對您有用。如果有疑問,可以聯系我們。
PHP應用在PHP-FPM中設立chroot,有很好的隔離作用,提高系統平安性,但是要想建立一個合理的PHP-FPM Chroot環境難度有點大,比用debootstrap等工具建立還要麻煩,下面通過參考相關資料,把PHP-FPM之Chroot執行環境整理出來,分享給大家.
PHP應用本文以Ubuntu 14.04.2為例,php-fpm使用的是 ppa:ondrej/php5-5.6 提供的PHP5.6版本,跟系統自帶以及Debian系統的php-fpm和系統目錄結構應該是一致的.CentOS請自行調整.
PHP應用php-fpm的chroot環境配置和所使用的服務器前端沒有關聯,也不強求Apache/Nginx進行chroot.當然那樣更平安――也更復雜.
PHP應用1.建立目錄結構
PHP應用chroot的目錄選擇為 /var/www/chroot ,其中頁面文件放置在 /var/www/chroot/public .
PHP應用執行下面的命令建立基本的目錄結構:
PHP應用
bash
mkdir -p /var/www/chroot/
cd /var/www/chroot
mkdir -p public bin dev tmp usr/sbin/ usr/share/zoneinfo/ var/run/nscd/ var/lib/php5/sessions var/www
cp -a /dev/zero /dev/urandom /dev/null dev/ #注3
chmod --reference=/tmp tmp/
chmod --reference=/var/lib/php5/sessions var/lib/php5/sessions #注4
chown -R root:root . #注2
chown -R www-data:www-data public/ #注2
cd var/www
ln -s ../.. chroot #注1
PHP應用下面是此時目錄結構,之后還會添加一些新的東西:
PHP應用
/var/www/chroot/
├── bin
├── dev
│ ├── null
│ ├── urandom
│ └── zero
├── public
├── tmp
├── usr
│ ├── sbin
│ └── share
│ └── zoneinfo
└── var
├── lib
│ └── php5
│ └── sessions
├── run
│ └── nscd
└── www
└── chroot -> ../.. #注1
PHP應用注1:這個軟連接用于解決Apache/nginx傳給php-fpm的 SCRIPT_FILENAME 在進入chroot后找不到文件(拜訪php頁面返回"File not found")的問題.
PHP應用以nginx為例,通常設置 SCRIPT_FILENAME 為 $document_root$fastcgi_script_name ,傳給php-fpm的腳本路徑就是 /var/www/chroot/public/index.php .而由于php-fpm處在chroot環境下,所以它實際試圖去拜訪的路徑就變成了 /var/www/chroot + /var/www/chroot/public/index.php 當然是不存在的.
PHP應用所以使用一個軟連接把chroot環境下的 /var/www/chroot 鏈接到根目錄,就能夠正常拜訪腳本了.
PHP應用當然也可以將 SCRIPT_FILENAME 設置成 /public$fastcgi_script_name .但是這樣硬編碼不利于配置的遷移,僅能用于chroot的環境,切換回非chroot環境的話還必要修改配置.所以不建議這么做.(順便說一句,有很多老教程里也不使用 $document_root ,直接硬編碼根目錄,當然也是不可取的)
PHP應用注2:chroot環境并不是100%平安的.由于php-fpm在chroot環境中的執行權限是www-data,仍然建議把非必要的目錄的擁有者設置為root來減少不必要的訪問權限.chroot不等于平安,參考 chroot最佳實踐 中列出的一些原則.從更平安的角度上講之后最好也將bin、lib、sbin等目錄的讀寫權限去掉,只留可執行權限,不過也沒大差別了……
PHP應用注3:cp -a除了拷貝文件內容外也會復制文件的權限、模式等信息,可以很便利的直接拿來拷貝zero、urandom和null這三個關鍵的設備文件.mknod似乎是更為穩妥的方式,不過cp -a我使用起來似乎也沒問題.
PHP應用注4:chmod --reference=XXX會參考XXX的權限設置后面的權限.tmp就不提了,關鍵是后面的 var/lib/php5/sessions 是php存放session文件的目錄,必要讓www-data有讀寫的權限.建議設置完之后再看一眼.當然后面會有測試.
PHP應用2.PHP-FPM的配置
PHP應用建立一個新的php-fpm的執行pool來搭建chroot環境.并不建議直接修改php-fpm.conf,因為這樣是全局生效的,如果有多個php站點的話會共用一套chroot環境.
PHP應用其實很多php-fpm的教程都忽略了php-fpm的pool的配置,導致很多人一臺服務器上所有站點都共用一套配置,尤其是共用一套php.ini的配置,實際上是不合理的.應當根據站點的需求單獨建立pool并在其中調整參數.
PHP應用在 /etc/php5/fpm/pool.d/ 下新建 chroot.conf (注意必需以.conf結尾,才能被php-fpm.conf調用):
PHP應用
[chroot]
user = www-data
group = www-data
listen = /var/run/php-chroot.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
chroot = /var/www/chroot
chdir = /public
;security.limit_extensions = .php
php_flag[display_errors] = on
php_value[date.timezone] = Asia/Hong_Kong
;php_admin_value[session.gc_probability] = 1
;php_admin_value[open_basedir] = "/tmp/:/public/:/var/www/chroot/public/"
PHP應用前面的參數都比擬熟悉了.只需要簡單的設置chroot為配置好的環境根目錄就可以開啟chroot了.通過執行 php5-fpm -t 測試一下之后,用 service php5-fpm reload 即可啟用新的pool.當然Apache/nginx對應的配置中要設置好后端.
PHP應用提一下最后幾行.倒數第四行打開了 display_errors ,以便之后對chroot下的php的功能進行測試,測試完了記得注釋掉.
PHP應用設置 session.gc_probability 允許php進程自行對session進行刪除回收.正常情況下session是由php添加的cron任務清理的,但是似乎php不會自動清理chroot環境下的session.當然也可以自己在cron.d下添加自動執行的腳原來清理,就不用開啟這個選項了.
PHP應用3.修復Chroot環境下PHP的各項功能
PHP應用在/var/www/chroot/public下新建一個test.php,寫入以下內容:
PHP應用這里主要測試的功能是:session、DNS解析、時間和日期、郵件mail()函數.
PHP應用拜訪上面的測試頁面,提示No such directory or file或者Permission denied說明session配置不正確. gethostbyname 返回的不是127.0.0.1或者::1,則說明DNS解析沒有生效.提示 timezone database is corrupt 之類的,說明時間和日期有錯誤.mail()也會有各種錯誤提示.
PHP應用session就不提了,設置好目錄權限就沒有問題.主要處理一下后面三個問題,也是php的chroot環境主要必要處理的內容.
PHP應用3.1 域名解析/時區等問題
PHP應用mail()的解決辦法大同小異,放后面談.前面的域名解析等問題這里我介紹兩種解決辦法.辦法1是參考Kienzl的簡便辦法,辦法2是大部分教程采用的辦法.
PHP應用辦法1:使用nscd
PHP應用nscd是(e)glibc的“Name Service Caching Daemon”.除了處理gethostbyname()這樣的函數外,也處理getpwnam()等需要拜訪/etc/passwd的函數.(e)glibc拜訪nscd的unix socket, /var/run/nscd/socket 來通過nscd獲取這些內容,如果不能連接到nscd則轉而自行進行解析.
PHP應用也就是說,只要裝好nscd,并且讓chroot環境里的程序能夠訪問到socket連接上nscd,就可以把chroot環境內的解析哀求轉由chroot外順利進行了.由于/var/run一般是tmpfs,硬鏈接無法跨文件系統使用,所以可以使用 mount -bind 來把/var/run/nscd目錄mount到chroot環境中同樣的位置去即可.
PHP應用同樣的道理,用 mount -bind 把/usr/share/zoneinfo目錄mount到chroot環境里,配合在php-fpm的pool里設置date.timezone就可以非常直接而暴力的辦理時區問題.
PHP應用先執行 apt-get install nscd 安裝nscd,然后為了能夠讓 mount -bind 自動執行,把下面的腳本存為 /etc/init.d/php-chroot
PHP應用
bash
#!/bin/sh
### BEGIN INIT INFO
# Provides: php5-fpm-chroot-setup
# Required-Start: nscd
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Bind-mounts needed sockets and data into a php-fpm-chroot
### END INIT INFO
CHROOT=/var/www/chroot
DIRS="/var/run/nscd /usr/share/zoneinfo"
case "$1" in
start)
$0 stop 2>/dev/null
for d in $DIRS; do
mkdir -p "${CHROOT}$7la94w5njlq9"
mount --bind -o ro "$7la94w5njlq9" "${CHROOT}$7la94w5njlq9"
done
;;
stop)
for d in $DIRS; do
umount "${CHROOT}$7la94w5njlq9"
done
;;
*)
echo "Usage: $N {start|stop}" >&2
exit 1
;;
esac
exit 0
PHP應用執行 update-rc.d php-chroot defaults 來讓腳本在啟動時執行.如果有多個chroot環境以及多個目錄必要bind-mount,可以自行添加一個循環改寫.
PHP應用這個方法的好處是簡單易行,不需要拷貝大量etc下的配置文件和庫文件到chroot環境中.使用nscd在解決域名訪問的問題過程中也順道解決了/etc/passwd和/etc/group.但是bind-mount和nscd的平安性尚沒有確切的說法,只能說so far so good.另外 mount -bind 會消耗一定的系統資源,有評論稱大約一個mount 大概會消耗500k內存,所以對于大量的chroot環境(幾百個)不見得適合.
PHP應用辦法2:拷貝/etc配置文件和庫文件
PHP應用這是最傳統而常用的辦法,也相對比較復雜.到底拷貝哪些配置、哪些庫文件因發行版和軟件版本而異,很難有定論也不好調試.而且一旦系統升級,對應的庫文件也需要進行更新,工作量很大.我沒有采用這個辦法,但是簡要的介紹一些比較靠譜的辦法分享一下.
PHP應用域名解析.必要拷貝/etc/resolv.conf,/etc/hosts,/etc/nsswitch.conf到chroot環境下的etc目錄下.還必要拷貝一系列的庫文件,主要是libnss_*.so,libresolv.so,libsoftokn3.so.具體libnss_*.so拷貝哪些,可以打開nsswitch.conf看列出了哪些.
PHP應用時區配置.拷貝/etc/localtime,/usr/share/zoneinfo/zone.tab,和/usr/share/zoneinfo目錄下所使用時區的文件.
PHP應用其它常用配置./etc/passwd和/etc/group有時也是必要的,但是內容 似乎可以偽造 ,至少可以選擇性的填寫不用完全拷貝主系統里的.
PHP應用如果使用的時候仍然出現問題,可以使用strace來查看php進行了哪些調用使用了哪些庫文件.先執行:
PHP應用bash
strace -p 進程pid -o chroot1.txt&? #有多個子進程就修改pid執行多次,輸出改為chroot2/3.txt存到不同文件里
此時在頁面里執行各種函數,然后查看輸出文件里記錄了哪些庫文件,對應拷貝到chroot環境里即可.
PHP應用這個方法很麻煩,尤其是第一次安裝設置和后續系統更新時.當然身為運維人員寫寫shell腳本簡化工作肯定是基本功了.這種方法沒有額外的內存消耗,可以部署大量chroot環境,當然硬盤消耗會高一點,而且平安性也經歷了長久的考驗
PHP應用3.2 修復mail()
PHP應用如果是使用WordPress,也可以利用MailChimp等插件不使用系統自身的郵件服務.事實上因為垃圾郵件的標準日益嚴格,和VPS主機商的限制,我現在更傾向于干脆不在系統里部署郵件服務了,所以php的mail()函數算是被廢掉了……當然如果必要的話也可以很簡單的設置好的.
PHP應用php的mail()函數是使用system()調用sendmail進行郵件發送操作,所以必要chroot環境里有能夠調用的sendmail程序即可.常見的替代品是mini_sendmail,這里多介紹ssmtp,msmtp也類似.
PHP應用前提:處理/bin/sh
PHP應用system()調用產生的命令行是 /bin/sh -c command .在chroot環境中調用外部程序必需存在/bin/sh,一個基本的shell.通常選擇拷貝dash:
PHP應用注意運行 ldd /bin/dash 觀察必要拷貝哪些庫文件.我這里的回顯是:
PHP應用但是!
PHP應用前面那句 “必需存在/bin/sh,一個基本的shell” 其實并不是真的,對于mail()只要有一個能接受-c參數調用后面的命令的程序就可以了.所以Kienzl寫了這樣一個程序:
PHP應用
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXARG 64
int main( int argc, char* const argv[] ) {
char* args[ MAXARG ] = {};
if( argc < 3 || strcmp( argv[1], "-c" ) != 0 ) {
fprintf( stderr, "Usage: %s -c <cmd>\n", argv[0] );
return 1;
}
{
char* token;
int i = 0;
char* argStr = strdup( argv[2] );
while( ( token = strsep( &argStr, " " ) ) != NULL ) {
if( token && strlen( token ) )
args[ i++ ] = token;
if( i >= MAXARG )
return 2;
}
}
return execvp( args[0], args );
}
PHP應用保留成sh.c執行: gcc sh.c -o sh -static 然后把sh拷貝到chroot環境的/bin目錄下即可.
PHP應用這樣一個不完全的shell從一定程度上也算是增強了chroot環境的平安性了.
PHP應用辦法1:使用mini_sendmail
PHP應用mini_sendmail似乎專為chroot環境而生.調用mini_sendmail后,它會轉而拜訪本機的25端口,通過本機的郵件服務來發送郵件.所以如果主環境有安裝postfix/exim4等郵件服務的話可以使用mini_sendmail來在chroot環境中發送郵件,這是最簡單的方法.
PHP應用mini_sendmail的安裝很簡單:
PHP應用最后一行自行修改chroot環境的目錄.切記要拷貝到chroot環境的/usr/sbin目錄下并且命名為sendmail.否則的話要在pool里自行設置ini參數的sendmail_path來指導php找到sendmail程序.
PHP應用由于mini_sendmail默認便是靜態鏈接,所以也無需拷貝其它的庫文件了.
PHP應用辦法2:使用ssmtp/msmtp
PHP應用對于本機沒有安裝郵件服務的情況,就不能使用mini_sendmail了.ssmtp和msmtp都支持把接收到的郵件發送哀求轉而通過其它SMTP服務器來發送.需要注意的是由于ssl支持需要更多更復雜的庫文件和配置,所以不建議為兩者編譯ssl支持……下面以ssmtp為例介紹一下.
PHP應用
bash
wget ftp://ftp.debian.org/debian/pool/main/s/ssmtp/ssmtp_2.64.orig.tar.bz2
tar jxf ssmtp_2.64.orig.tar.bz2
cd ssmtp_2.64
./configure --prefix=/ #別忘了prefix
make #千萬別手抖make install
cp ssmtp /var/www/chroot/usr/sbin
mkdir -p /var/www/chroot/etc/ssmtp
cp ssmtp.conf revaliases /var/www/chroot/etc/ssmtp #配置文件
cd /var/www/chroot/usr/sbin
ln -s ssmtp sendmail
PHP應用同樣記得ldd然后把對應的庫文件拷貝過去.另外ssmtp必要/etc/passwd和/etc/group,如果上面沒有使用nscd必要拷貝/偽造這兩個文件.
PHP應用ssmtp必要配置.ssmtp.conf文件配置如下:
PHP應用
bash
root=admin@example.com #其實這行好像可以亂寫
mailhub=smtp.example.com #smtp服務器地址
hostname=myexample.com #此處的hostname似乎會用于產生默認的“root@myexample.com”形式的發件人地址
AuthUser=admin@example.com #此處使用真實的登錄用戶名
AuthPass=password #暗碼
FromLineOverride=YES #允許改寫發件人
PHP應用revaliases里配置每個用戶在使用ssmtp時使用的“發件人”地址和smtp服務器地址.可以不配置,但是文件要有.具體格式是:
PHP應用可以使用chroot(指真正的chroot命令)做個測試:
PHP應用此時php的mail()函數應該就可用了.
PHP應用4.其它問題
PHP應用配置完chroot環境跋文得將php的pool設置里display_error關閉.
MySQL的連接可能會遇到問題 ,因為如果填寫localhost的話php會試圖尋找MySQL的unix socket來訪問mysqld.填寫127.0.0.1通過TCP連接就沒有問題了
完成后的目錄結構,以我為例給大家參考一下:
PHP應用
/var/www/chroot/
├── bin
│ └── sh
├── dev
│ ├── null
│ ├── urandom
│ └── zero
├── etc
│ └── ssmtp
│ ├── revaliases
│ └── ssmtp.conf
├── lib
│ └── libc.so.6
├── lib64
│ └── ld-linux-x86-64.so.2
├── public
├── tmp
├── usr
│ ├── sbin
│ │ ├── sendmail -> ssmtp
| │ └── ssmtp
│ └── share
│ └── zoneinfo
│ ├── 大量時區的目錄結構
│ └── zone.tab
└── var
├── lib
│ └── php5
│ └── sessions
├── run
│ └── nscd
│ ├── nscd.pid
│ └── socket
└── www
└── chroot -> ../..
PHP應用以上便是本文的全部內容,希望大家喜歡.
《PHP教程:PHP-FPM之Chroot執行環境詳解》是否對您有啟發,歡迎查看更多與《PHP教程:PHP-FPM之Chroot執行環境詳解》相關教程,學精學透。維易PHP學院為您提供精彩教程。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/8939.html