摘要:原文地址建立的執(zhí)行環(huán)境中可以設(shè)立,起到非常好的隔離效果,增強系統(tǒng)安全性。的配置建立一個新的的執(zhí)行來搭建環(huán)境。并不建議直接修改,因為這樣是全局生效的,如果有多個站點的話會共用一套環(huán)境。設(shè)置允許進程自行對進行刪除回收。
原文地址:建立PHP-FPM的Chroot執(zhí)行環(huán)境
php-fpm中可以設(shè)立chroot,起到非常好的隔離效果,增強系統(tǒng)安全性。但是建立一個合理可用的php-fpm chroot環(huán)境則有些難度,比起能夠利用debootstrap等工具進行的建立完整的chroot環(huán)境還要麻煩一點。網(wǎng)上有一部分教程,但大多比較雜亂或者老舊,對步驟也缺乏說明。這里參考很多資料把php-fpm的chroot建立重新梳理一遍。
本文以Ubuntu 14.04.2為例,php-fpm使用的是ppa:ondrej/php5-5.6提供的PHP5.6版本,跟系統(tǒng)自帶以及Debian系統(tǒng)的php-fpm和系統(tǒng)目錄結(jié)構(gòu)應(yīng)該是一致的。CentOS請自行調(diào)整。
php-fpm的chroot環(huán)境配置和所使用的服務(wù)器前端沒有關(guān)聯(lián),也不強求Apache/Nginx進行chroot。當然那樣更安全——也更復(fù)雜。
1.建立目錄結(jié)構(gòu)chroot的目錄選擇為/var/www/chroot,其中頁面文件放置在/var/www/chroot/public。
執(zhí)行下面的命令建立基本的目錄結(jié)構(gòu):
bashmkdir -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
下面是此時目錄結(jié)構(gòu),之后還會添加一些新的東西:
/var/www/chroot/ ├── bin ├── dev │?? ├── null │?? ├── urandom │?? └── zero ├── public ├── tmp ├── usr │?? ├── sbin │?? └── share │?? └── zoneinfo └── var ├── lib │?? └── php5 │?? └── sessions ├── run │?? └── nscd └── www └── chroot -> ../.. #注1
注1: 這個軟連接用于解決Apache/nginx傳給php-fpm的SCRIPT_FILENAME在進入chroot后找不到文件(訪問php頁面返回"File not found")的問題。
以nginx為例,通常設(shè)置SCRIPT_FILENAME為$document_root$fastcgi_script_name,傳給php-fpm的腳本路徑就是/var/www/chroot/public/index.php。而由于php-fpm處在chroot環(huán)境下,所以它實際試圖去訪問的路徑就變成了/var/www/chroot+/var/www/chroot/public/index.php當然是不存在的。
所以使用一個軟連接把chroot環(huán)境下的/var/www/chroot鏈接到根目錄,就能夠正常訪問腳本了。
當然也可以將SCRIPT_FILENAME設(shè)置成/public$fastcgi_script_name。但是這樣硬編碼不利于配置的遷移,僅能用于chroot的環(huán)境,切換回非chroot環(huán)境的話還需要修改配置。所以不建議這么做。(順便說一句,有很多老教程里也不使用$document_root,直接硬編碼根目錄,當然也是不可取的)
注2: chroot環(huán)境并不是100%安全的。由于php-fpm在chroot環(huán)境中的執(zhí)行權(quán)限是www-data,仍然建議把非必要的目錄的擁有者設(shè)置為root來減少不必要的訪問權(quán)限。chroot不等于安全,參考chroot最佳實踐中列出的一些原則。從更安全的角度上講之后最好也將bin、lib、sbin等目錄的讀寫權(quán)限去掉,只留可執(zhí)行權(quán)限,不過也沒大差別了……
注3: cp -a除了拷貝文件內(nèi)容外也會復(fù)制文件的權(quán)限、模式等信息,可以很方便的直接拿來拷貝zero、urandom和null這三個關(guān)鍵的設(shè)備文件。mknod似乎是更為穩(wěn)妥的方式,不過cp -a我使用起來似乎也沒問題。
注4: chmod --reference=XXX會參考XXX的權(quán)限設(shè)置后面的權(quán)限。tmp就不提了,關(guān)鍵是后面的var/lib/php5/sessions是php存放session文件的目錄,需要讓www-data有讀寫的權(quán)限。建議設(shè)置完之后再看一眼。當然后面會有測試。
2.PHP-FPM的配置建立一個新的php-fpm的執(zhí)行pool來搭建chroot環(huán)境。并不建議直接修改php-fpm.conf,因為這樣是全局生效的,如果有多個php站點的話會共用一套chroot環(huán)境。
其實很多php-fpm的教程都忽略了php-fpm的pool的配置,導(dǎo)致很多人一臺服務(wù)器上所有站點都共用一套配置,尤其是共用一套php.ini的配置,實際上是不合理的。應(yīng)當根據(jù)站點的需求多帶帶建立pool并在其中調(diào)整參數(shù)。
在/etc/php5/fpm/pool.d/下新建chroot.conf(注意必須以.conf結(jié)尾,才能被php-fpm.conf調(diào)用):
[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/"
前面的參數(shù)都比較熟悉了。只需要簡單的設(shè)置chroot為配置好的環(huán)境根目錄就可以開啟chroot了。通過執(zhí)行php5-fpm -t測試一下之后,用service php5-fpm reload即可啟用新的pool。當然Apache/nginx對應(yīng)的配置中要設(shè)置好后端。
提一下最后幾行。倒數(shù)第四行打開了display_errors,以便之后對chroot下的php的功能進行測試,測試完了記得注釋掉。
設(shè)置session.gc_probability允許php進程自行對session進行刪除回收。正常情況下session是由php添加的cron任務(wù)清理的,但是似乎php不會自動清理chroot環(huán)境下的session。當然也可以自己在cron.d下添加自動執(zhí)行的腳本來清理,就不用開啟這個選項了。
3.修復(fù)Chroot環(huán)境下PHP的各項功能在/var/www/chroot/public下新建一個test.php,寫入以下內(nèi)容:
php這里主要測試的功能是:session、DNS解析、時間和日期、郵件mail()函數(shù)。
訪問上面的測試頁面,提示No such directory or file或者Permission denied說明session配置不正確。gethostbyname返回的不是127.0.0.1或者::1,則說明DNS解析沒有生效。提示timezone database is corrupt之類的,說明時間和日期有錯誤。mail()也會有各種錯誤提示。
session就不提了,設(shè)置好目錄權(quán)限就沒有問題。主要處理一下后面三個問題,也是php的chroot環(huán)境主要需要處理的內(nèi)容。
3.1 域名解析/時區(qū)等問題mail()的解決方法大同小異,放后面談。前面的域名解析等問題這里我介紹兩種解決方法。方法1是參考Kienzl的簡便方法,方法2是大部分教程采用的方法。
方法1:使用nscdnscd是(e)glibc的“Name Service Caching Daemon”。除了處理gethostbyname()這樣的函數(shù)外,也處理getpwnam()等需要訪問/etc/passwd的函數(shù)。(e)glibc訪問nscd的unix socket,/var/run/nscd/socket來通過nscd獲取這些內(nèi)容,如果不能連接到nscd則轉(zhuǎn)而自行進行解析。
也就是說,只要裝好nscd,并且讓chroot環(huán)境里的程序能夠訪問到socket連接上nscd,就可以把chroot環(huán)境內(nèi)的解析請求轉(zhuǎn)由chroot外順利進行了。由于/var/run一般是tmpfs,硬鏈接無法跨文件系統(tǒng)使用,所以可以使用mount -bind來把/var/run/nscd目錄mount到chroot環(huán)境中同樣的位置去即可。
同樣的道理,用mount -bind把/usr/share/zoneinfo目錄mount到chroot環(huán)境里,配合在php-fpm的pool里設(shè)置date.timezone就可以非常直接而暴力的解決時區(qū)問題。
先執(zhí)行apt-get install nscd安裝nscd,然后為了能夠讓mount -bind自動執(zhí)行,把下面的腳本存為/etc/init.d/php-chroot
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}$vlnv5hp" mount --bind -o ro "$rvrb3db" "${CHROOT}$5vf59vv" done ;; stop) for d in $DIRS; do umount "${CHROOT}$zfxtxbr" done ;; *) echo "Usage: $N {start|stop}" >&2 exit 1 ;; esac exit 0執(zhí)行update-rc.d php-chroot defaults來讓腳本在啟動時執(zhí)行。如果有多個chroot環(huán)境以及多個目錄需要bind-mount,可以自行添加一個循環(huán)改寫。
這個方法的好處是簡單易行,不需要拷貝大量etc下的配置文件和庫文件到chroot環(huán)境中。使用nscd在解決域名訪問的問題過程中也順道解決了/etc/passwd和/etc/group。但是bind-mount和nscd的安全性尚沒有確切的說法,只能說so far so good。另外mount -bind會消耗一定的系統(tǒng)資源,有評論稱大約一個mount 大概會消耗500k內(nèi)存,所以對于大量的chroot環(huán)境(幾百個)不見得適合。
方法2:拷貝/etc配置文件和庫文件這是最傳統(tǒng)而常用的方法,也相對比較復(fù)雜。到底拷貝哪些配置、哪些庫文件因發(fā)行版和軟件版本而異,很難有定論也不好調(diào)試。而且一旦系統(tǒng)升級,對應(yīng)的庫文件也需要進行更新,工作量很大。我沒有采用這個方法,但是簡要的介紹一些比較靠譜的方法分享一下。
域名解析。需要拷貝/etc/resolv.conf,/etc/hosts,/etc/nsswitch.conf到chroot環(huán)境下的etc目錄下。還需要拷貝一系列的庫文件,主要是libnss_*.so,libresolv.so,libsoftokn3.so。具體libnss_*.so拷貝哪些,可以打開nsswitch.conf看列出了哪些。
時區(qū)配置。拷貝/etc/localtime,/usr/share/zoneinfo/zone.tab,和/usr/share/zoneinfo目錄下所使用時區(qū)的文件。
其它常用配置。/etc/passwd和/etc/group有時也是需要的,但是內(nèi)容似乎可以偽造,至少可以選擇性的填寫不用完全拷貝主系統(tǒng)里的。
如果使用的時候仍然出現(xiàn)問題,可以使用strace來查看php進行了哪些調(diào)用使用了哪些庫文件。先執(zhí)行:
bashps aux | grep php | grep "chroot" #chroot是php的pool名查看pool的進程pid(可以在pool設(shè)置里先把子進程數(shù)目限制到1個方便調(diào)試)。然后執(zhí)行:
bashstrace -p 進程pid -o chroot1.txt& #有多個子進程就修改pid執(zhí)行多次,輸出改為chroot2/3.txt存到不同文件里此時在頁面里執(zhí)行各種函數(shù),然后查看輸出文件里記錄了哪些庫文件,對應(yīng)拷貝到chroot環(huán)境里即可。
這個方法很麻煩,尤其是第一次安裝設(shè)置和后續(xù)系統(tǒng)更新時。當然身為運維人員寫寫shell腳本簡化工作肯定是基本功了。這種方法沒有額外的內(nèi)存消耗,可以部署大量chroot環(huán)境,當然硬盤消耗會高一點,而且安全性也經(jīng)歷了長久的考驗
3.2 修復(fù)mail()如果是使用WordPress,也可以利用MailChimp等插件不使用系統(tǒng)自身的郵件服務(wù)。事實上因為垃圾郵件的標準日益嚴格,和VPS主機商的限制,我現(xiàn)在更傾向于干脆不在系統(tǒng)里部署郵件服務(wù)了,所以php的mail()函數(shù)算是被廢掉了……當然如果需要的話也可以很簡單的設(shè)置好的。
php的mail()函數(shù)是使用system()調(diào)用sendmail進行郵件發(fā)送操作,所以需要chroot環(huán)境里有能夠調(diào)用的sendmail程序即可。常見的替代品是mini_sendmail,這里多介紹ssmtp,msmtp也類似。
前提:處理/bin/shsystem()調(diào)用產(chǎn)生的命令行是/bin/sh -c command。在chroot環(huán)境中調(diào)用外部程序必須存在/bin/sh,一個基本的shell。通常選擇拷貝dash:
bash#cp /bin/dash /var/www/chroot/bin/sh注意運行ldd /bin/dash觀察需要拷貝哪些庫文件。我這里的回顯是:
bashldd /bin/dash linux-vdso.so.1 => (0x00007fff779fe000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f165620f000) /lib64/ld-linux-x86-64.so.2 (0x00007f16567fc000)第一條那個只列了個文件名,=>后面也沒有文件的基本上都是不用管的。剩下的庫文件基本的原則是如果列出的是/lib64,就拷貝到chroot環(huán)境下的/lib64,如果列出的是/lib,雖然有很多發(fā)行版,大部分庫文件包括libc.so是在/lib/x86_64-linux-gnu/目錄下的,也直接拷貝到chroot環(huán)境的/lib目錄下即可,是可以正常找到的。
但是!
前面那句“必須存在/bin/sh,一個基本的shell”其實并不是真的,對于mail()只要有一個能接受-c參數(shù)調(diào)用后面的命令的程序就可以了。所以Kienzl寫了這樣一個程序:
c#include#include #include #include ? #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 ", 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 ); } 保存成sh.c執(zhí)行:gcc sh.c -o sh -static然后把sh拷貝到chroot環(huán)境的/bin目錄下即可。
這樣一個不完全的shell從一定程度上也算是增強了chroot環(huán)境的安全性了。
方法1:使用mini_sendmailmini_sendmail似乎專為chroot環(huán)境而生。調(diào)用mini_sendmail后,它會轉(zhuǎn)而訪問本機的25端口,通過本機的郵件服務(wù)來發(fā)送郵件。所以如果主環(huán)境有安裝postfix/exim4等郵件服務(wù)的話可以使用mini_sendmail來在chroot環(huán)境中發(fā)送郵件,這是最簡單的方法。
mini_sendmail的安裝很簡單:
bashwget http://www.acme.com/software/mini_sendmail/mini_sendmail-1.3.8.tar.gz tar zxf mini_sendmail-1.3.8.tar.gz cd mini_sendmail-1.3.8 make cp mini_sendmail /var/www/chroot/usr/sbin/sendmail最后一行自行修改chroot環(huán)境的目錄。切記要拷貝到chroot環(huán)境的/usr/sbin目錄下并且命名為sendmail。否則的話要在pool里自行設(shè)置ini參數(shù)的sendmail_path來指導(dǎo)php找到sendmail程序。
由于mini_sendmail默認就是靜態(tài)鏈接,所以也無需拷貝其它的庫文件了。
方法2:使用ssmtp/msmtp對于本機沒有安裝郵件服務(wù)的情況,就不能使用mini_sendmail了。ssmtp和msmtp都支持把接收到的郵件發(fā)送請求轉(zhuǎn)而通過其它SMTP服務(wù)器來發(fā)送。需要注意的是由于ssl支持需要更多更復(fù)雜的庫文件和配置,所以不建議為兩者編譯ssl支持……下面以ssmtp為例介紹一下。
bashwget 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同樣記得ldd然后把對應(yīng)的庫文件拷貝過去。另外ssmtp需要/etc/passwd和/etc/group,如果上面沒有使用nscd需要拷貝/偽造這兩個文件。
ssmtp需要配置。ssmtp.conf文件配置如下:
bashroot=admin@example.com #其實這行好像可以亂寫 mailhub=smtp.example.com #smtp服務(wù)器地址 hostname=myexample.com #此處的hostname似乎會用于產(chǎn)生默認的“root@myexample.com”形式的發(fā)件人地址 AuthUser=admin@example.com #此處使用真實的登錄用戶名 AuthPass=password #密碼 FromLineOverride=YES #允許改寫發(fā)件人revaliases里配置每個用戶在使用ssmtp時使用的“發(fā)件人”地址和smtp服務(wù)器地址。可以不配置,但是文件要有。具體格式是:
bash# 本地用戶名:發(fā)件人地址:smtp服務(wù)器[:端口(默認25)] root:admin@example.com:smtp.example.com www-data:noreply@example.com:smtp.example.com可以使用chroot(指真正的chroot命令)做個測試:
bashchroot /var/www/chroot /bin/sh #此時/bin/sh一定要是真正的shell echo "Subject: test"|sendmail -v username@server.com #替換郵件地址為自己的此時php的mail()函數(shù)應(yīng)該就可用了。
4.其它問題配置完chroot環(huán)境后記得將php的pool設(shè)置里display_error關(guān)閉。
MySQL的連接可能會遇到問題,因為如果填寫localhost的話php會試圖尋找MySQL的unix socket來訪問mysqld。填寫127.0.0.1通過TCP連接就沒有問題了
完成后的目錄結(jié)構(gòu),以我為例給大家參考一下:
/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 │?? ├── 大量時區(qū)的目錄結(jié)構(gòu) │?? └── zone.tab └── var ├── lib │?? └── php5 │?? └── sessions ├── run │?? └── nscd │?? ├── nscd.pid │?? └── socket └── www └── chroot -> ../..參考資料Setting up a chroot for PHP
Nginx + PHP-FPM with chroot
Chrooted PHP-FPM with Nginx on CentOS 6
Chroot with sSMTP
在嵌入式系統(tǒng)添加郵件發(fā)送功能
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/21050.html
摘要:等平臺平臺由于我開發(fā)以為主,所以就用的環(huán)境配置來學(xué)習(xí)。啟動進程的用戶和用戶組,進程運行的用戶必須要設(shè)置。模式模式,表示啟動進程是動態(tài)分配的,隨著請求量動態(tài)變化的。 centos等linux平臺 /usr/local/php/php /usr/local/php/etc/php.ini /usr/local/php/sbin/php-fpm /usr/local/php/etc/php-...
摘要:等平臺平臺由于我開發(fā)以為主,所以就用的環(huán)境配置來學(xué)習(xí)。啟動進程的用戶和用戶組,進程運行的用戶必須要設(shè)置。模式模式,表示啟動進程是動態(tài)分配的,隨著請求量動態(tài)變化的。 centos等linux平臺 /usr/local/php/php /usr/local/php/etc/php.ini /usr/local/php/sbin/php-fpm /usr/local/php/etc/php-...
摘要:等平臺平臺由于我開發(fā)以為主,所以就用的環(huán)境配置來學(xué)習(xí)。啟動進程的用戶和用戶組,進程運行的用戶必須要設(shè)置。模式模式,表示啟動進程是動態(tài)分配的,隨著請求量動態(tài)變化的。 centos等linux平臺 /usr/local/php/php /usr/local/php/etc/php.ini /usr/local/php/sbin/php-fpm /usr/local/php/etc/php-...
閱讀 3118·2021-11-15 18:14
閱讀 1773·2021-09-22 10:51
閱讀 3283·2021-09-09 09:34
閱讀 3505·2021-09-06 15:02
閱讀 1013·2021-09-01 11:40
閱讀 3186·2019-08-30 13:58
閱讀 2523·2019-08-30 11:04
閱讀 1081·2019-08-28 18:31