關於nginx/php-fpm/apache mod_php中的安全配置,可參考我以前的另一個文章:php
《正確設置nginx/php-fpm/apache 提升網站安全性 防止被掛木馬》linux
http://zhangxugg-163-com.iteye.com/blog/1171572nginx
1、基礎知識準備shell
在任何配置開始前,必定要搞清楚這幾個概念,若是這幾個概念沒有完全弄清楚,就沒法理解後續的配置的意義了, 有經驗的系統管理員可跳過。apache
1. 站點文件全部者帳戶是什麼,文件的權限又是什麼?windows
2.nginx, php-fpm, apache用什麼帳戶運行?緩存
3.網站的哪些目錄和文件是可寫的?這裏的可寫,是指對於nginx ? php-fpm ? 仍是apache ?安全
4.如何禁止php代碼被執行?框架
Linux的最基本的權限是:文件的全部者,對其所屬全部文件都有任何權限(root權限不受限制),讀寫執行權限分別被標識爲4 2 1yii
我看到最多的是,一些系統管理員爲了省事,讓php-fpm/apache以網站文件全部者,這樣方便php程序在任何位置生成文件, 但這樣配置卻可能形成嚴重的安全問題。
上面幾個問題的回覆:
1.在linux目錄中,使用ls -l命令便可查看當前目錄全部者,第三、4列分別文件所屬於的用戶/組,如圖示,這是yii框架的protected目錄中的文件列表
咱們能夠看到,文件全部者和組是ftp, runtime目錄權限是任何人有讀寫執行權限.
2.站點中,每每須要可寫目錄,用於運行時生成文件(緩存、靜態文件、附件上傳等),因此這個可寫,是針對php程序自己而言的,nginx+php-fpm模式下,nginx只是負責把請求轉發給php-fpm進程,因此最終的生成文件是由php-fpm產生的。可是Apache mod_php卻有所不一樣,mod_php做爲apache的一個模塊,其權限繼承自apache, 故說成apache的可寫目錄,也不爲錯。
能夠用命令 ps aux | egrep 'nginx|php-fpm|apache' 查看nginx/php-fpm/apache運行帳戶
3.與開發人員溝通,瞭解可寫目錄及其意義
4.若是禁止php代碼被執行?可能因爲程序代碼漏洞,木馬文件被上傳到了附件目錄,你可能認爲在linux中去掉這個目錄的執行權限就好了?
chmod a-x -R uploadfile
但這樣就致使apache沒法讀取此目錄的文件,致使附件文件沒法被訪問了。另外一方面,這種方式也是錯誤的。即使是去掉附件文件自己的執行權限(普通文件自己,是沒有執行權限),也是行不通的,要先了解php的運行機制。
php的經常使用運行方式有如下幾種:
A . 以nginx+php-fpm的方式運行
B. 以apache mod_php方式運行
C. 命令行下,使用php <filename.php> 方式運行
D. 在php腳本第一行添加:#!/usr/local/php/bin/php, 並給此文件添加執行權限,就能夠把它當成一shell腳本運行了。這種文件並不常見。
這幾種方式中,只有最後一種方式才須要執行權限,其它幾種方式下,只要php解釋器進程對php腳本有讀取權限,便可運行。關於如何禁止php腳本的執行,可參閱做者的上述文章。
2、safe_mode
php的安全模式備受爭議,由於它涉及系統配置,並且它是使用了windows的配置思想,在Linux環境中並不適合。簡單地說,開啓safe_mode後,php進程自己只容許打開屬於它本身的腳本文件。也就是說,在多站點環境中,咱們必須爲每一個站點創建一個用戶,並讓php進程以對應的帳戶權限運行, 這樣它能夠對本身的站點文件有最高權限,但對其它用戶的文件,則沒有任何權限。聽起來不錯,但事實上這個配置起來的工做量至關繁瑣並且極容易出錯:
1. 若是站點不少,須要創建大量帳戶,須要將站點目錄分別受權給這些用戶
2.php-fpm須要創建大量的進程池,並指定不一樣的帳戶身份, 可能形成fpm進程資源浪費
3.apachce不能配置多個運行帳戶,只能指定一個。
4.共享目錄(如/tmp, /dev/shm等須要單獨指定),並非一件容易的事。
可見,正由於safe_mode配置如此繁瑣, php新版將取消safe_mode的支持,PHP手冊上已經描述很清楚:
5. 若是站點要遷移到其它機器,用戶帳戶也須要徹底遷移,這也是很繁瑣的工做量。
安全模式自 PHP 5.3.0 起廢棄並將自 PHP 5.4.0 起移除。
因此,依賴安全模式的方式,在php新版本中將不會被支持,筆者編寫這個文章時,php 7.0.2已經發布。
3、爲何要用open_basedir
open_basedir 用於限制php進程能夠打開的目錄前綴,通常來講,php程序除了須要讀取本站點的文件外,還每每會用到/tmp /dev/shm目錄。
假設站點位於 /data/wwwroot/site.cn,在運行時要用到/tmp, /dev/shm, /proc目錄,那麼能夠在php.ini中這樣設置
open_basedir = /data/wwwroot/site.cn:/tmp:/dev/shm:/proc
若是php中使用include, require, fopen, gzopen等函數加載其它目錄文件,就會報錯:
require_once(): open_basedir restriction in effect. File(file.php) is not within the allowed path(s): (PATH)
Warning: require_once(file.php): failed to open stream: Operation not permitted in
Fatal error: require_once(): Failed opening required ...
這個參數在 php 5.2.3時只能在php.ini中配置,沒法在運行時配置。php 5.2.3時,能夠在任何位置設置。
顯然,針對一個有大量站點的主機, 使用多個php.ini的方式,就很是難以配置。方法有兩種:
1.在php-fpm.conf配置文件中,爲每一個進程池指定不一樣的限定目錄
[www]
php_admin_value[open_basedir] = /var/www/www.example.com:/usr/share/php5:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin
php_admin_value是指此值一旦設置,沒法在運行時被修改。但這種方法,卻並不被推薦的,由於每一個站點都須要創建一個進程池,有100個站點,就須要創建100個進程池,並且這些php進程,沒法互相使用,只能是站點獨享,形成資源極大浪費。
2.nginx經過fastcgi協議和php-fpm通訊時,能夠指定一些參數,用於在請求開始前,修改php的配置參數, 這是最爲方便有效的方法,強制推薦
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/:/dev/shm";
這是php-fpm特有的功能,表示從fastcgi客戶端能夠接收一些參數指定
因爲$document_root變量的引入,咱們就能夠直接批量配置了。
這樣一來,全部站點可共享同一個進程池,同時又解決了分別限制訪問目錄的問題。咱們能夠把這個指令加入到nginx的fastcgi_params配置文件中,這樣全部站點就當即生效,解決了難題
能夠用如下php代碼測試一下
<?php
echo ini_get('open_basedir');
ini_set('open_basedir', '/etc/');
echo ini_get('open_basedir');
可見已經設置爲所指望的限制,並沒有法在運行時進行修改的。 經過這個觸類旁通,咱們能夠在nginx根據須要指定php的各類配置了