天天看點

Nginx工作原理和優化、漏洞

Nginx工作原理和優化、漏洞。

1.  Nginx的子產品與工作原理

Nginx由核心和子產品組成,其中,核心的設計非常微小和簡潔,完成的工作也非常簡單,僅僅通過查找配置檔案将用戶端請求映射到一個location block(location是Nginx配置中的一個指令,用于URL比對),而在這個location中所配置的每個指令将會啟動不同的子產品去完成相應的工作。

Nginx的子產品從結構上分為核心子產品、基礎子產品和第三方子產品:

核心子產品:HTTP子產品、EVENT子產品和MAIL子產品

基礎子產品:HTTP Access子產品、HTTP FastCGI子產品、HTTP Proxy子產品和HTTP Rewrite子產品,

第三方子產品:HTTP Upstream Request Hash子產品、Notice子產品和HTTP Access Key子產品。

使用者根據自己的需要開發的子產品都屬于第三方子產品。正是有了這麼多子產品的支撐,Nginx的功能才會如此強大。

Nginx的子產品從功能上分為如下三類。

Handlers(處理器子產品)。此類子產品直接處理請求,并進行輸出内容和修改headers資訊等操作。Handlers處理器子產品一般隻能有一個。

Filters (過濾器子產品)。此類子產品主要對其他處理器子產品輸出的内容進行修改操作,最後由Nginx輸出。

Proxies (代理類子產品)。此類子產品是Nginx的HTTP Upstream之類的子產品,這些子產品主要與後端一些服務比如FastCGI等進行互動,實作服務代理和負載均衡等功能。

圖1-1展示了Nginx子產品正常的HTTP請求和響應的過程。

Nginx工作原理和優化、漏洞

                       圖1-1展示了Nginx子產品正常的HTTP請求和響應的過程。

Nginx本身做的工作實際很少,當它接到一個HTTP請求時,它僅僅是通過查找配置檔案将此次請求映射到一個location block,而此location中所配置的各個指令則會啟動不同的子產品去完成工作,是以子產品可以看做Nginx真正的勞動工作者。通常一個location中的指令會涉及一個handler子產品和多個filter子產品(當然,多個location可以複用同一個子產品)。handler子產品負責處理請求,完成響應内容的生成,而filter子產品對響應内容進行處理。

Nginx的子產品直接被編譯進Nginx,是以屬于靜态編譯方式。啟動Nginx後,Nginx的子產品被自動加載,不像Apache,首先将子產品編譯為一個so檔案,然後在配置檔案中指定是否進行加載。在解析配置檔案時,Nginx的每個子產品都有可能去處理某個請求,但是同一個處理請求隻能由一個子產品來完成。 

在工作方式上,Nginx分為單工作程序和多工作程序兩種模式。在單工作程序模式下,除主程序外,還有一個工作程序,工作程序是單線程的;在多工作程序模式下,每個工作程序包含多個線程。Nginx預設為單工作程序模式。

2.  Nginx+FastCGI運作原理

1、什麼是 FastCGI

FastCGI是一個可伸縮地、高速地在HTTP server和動态腳本語言間通信的接口。多數流行的HTTP server都支援FastCGI,包括Apache、Nginx和lighttpd等。同時,FastCGI也被許多腳本語言支援,其中就有PHP。

FastCGI是從CGI發展改進而來的。傳統CGI接口方式的主要缺點是性能很差,因為每次HTTP伺服器遇到動态程式時都需要重新啟動腳本解析器來執行解析,然後将結果傳回給HTTP伺服器。這在處理高并發通路時幾乎是不可用的。另外傳統的CGI接口方式安全性也很差,現在已經很少使用了。

FastCGI接口方式采用C/S結構,可以将HTTP伺服器和腳本解析伺服器分開,同時在腳本解析伺服器上啟動一個或者多個腳本解析守護程序。當HTTP伺服器每次遇到動态程式時,可以将其直接傳遞給FastCGI程序來執行,然後将得到的結果傳回給浏覽器。這種方式可以讓HTTP伺服器專一地處理靜态請求或者将動态腳本伺服器的結果傳回給用戶端,這在很大程度上提高了整個應用系統的性能。

2、Nginx+FastCGI運作原理

Nginx不支援對外部程式的直接調用或者解析,所有的外部程式(包括PHP)必須通過FastCGI接口來調用。FastCGI接口在Linux下是socket(這個socket可以是檔案socket,也可以是ip socket)。

wrapper:為了調用CGI程式,還需要一個FastCGI的wrapper(wrapper可以了解為用于啟動另一個程式的程式),這個wrapper綁定在某個固定socket上,如端口或者檔案socket。當Nginx将CGI請求發送給這個socket的時候,通過FastCGI接口,wrapper接收到請求,然後Fork(派生)出一個新的線程,這個線程調用解釋器或者外部程式處理腳本并讀取傳回資料;接着,wrapper再将傳回的資料通過FastCGI接口,沿着固定的socket傳遞給Nginx;最後,Nginx将傳回的資料(html頁面或者圖檔)發送給用戶端。這就是Nginx+FastCGI的整個運作過程,如圖1-3所示。

      是以,我們首先需要一個wrapper,這個wrapper需要完成的工作:

通過調用fastcgi(庫)的函數通過socket和ningx通信(讀寫socket是fastcgi内部實作的功能,對wrapper是非透明的)

排程thread,進行fork和kill

和application(php)進行通信

3、spawn-fcgi與PHP-FPM

       FastCGI接口方式在腳本解析伺服器上啟動一個或者多個守護程序對動态腳本進行解析,這些程序就是FastCGI程序管理器,或者稱為FastCGI引擎。 spawn-fcgi與PHP-FPM就是支援PHP的兩個FastCGI程序管理器。是以HTTPServer完全解放出來,可以更好地進行響應和并發處理。

       spawn-fcgi與PHP-FPM的異同:

       1)spawn-fcgi是HTTP伺服器lighttpd的一部分,目前已經獨立成為一個項目,一般與lighttpd配合使用來支援PHP。但是ligttpd的spwan-fcgi在高并發通路的時候,會出現記憶體洩漏甚至自動重新開機FastCGI的問題。即:PHP腳本處理器當機,這個時候如果使用者通路的話,可能就會出現白頁(即PHP不能被解析或者出錯)。

       2)Nginx是個輕量級的HTTP server,必須借助第三方的FastCGI處理器才可以對PHP進行解析,是以其實這樣看來nginx是非常靈活的,它可以和任何第三方提供解析的處理器實作連接配接進而實作對PHP的解析(在nginx.conf中很容易設定)。nginx也可以使用spwan-fcgi(需要一同安裝lighttpd,但是需要為nginx避開端口,一些較早的blog有這方面安裝的教程),但是由于spawn-fcgi具有上面所述的使用者逐漸發現的缺陷,現在慢慢減少用nginx+spawn-fcgi組合了。

       由于spawn-fcgi的缺陷,現在出現了第三方(目前已經加入到PHP core中)的PHP的FastCGI處理器PHP-FPM,它和spawn-fcgi比較起來有如下優點:

       由于它是作為PHP的patch更新檔來開發的,安裝的時候需要和php源碼一起編譯,也就是說編譯到php core中了,是以在性能方面要優秀一些;

同時它在處理高并發方面也優于spawn-fcgi,至少不會自動重新開機fastcgi處理器。是以,推薦使用Nginx+PHP/PHP-FPM這個組合對PHP進行解析。

      相對Spawn-FCGI,PHP-FPM在CPU和記憶體方面的控制都更勝一籌,而且前者很容易崩潰,必須用crontab進行監控,而PHP-FPM則沒有這種煩惱。

       FastCGI 的主要優點是把動态語言和HTTP Server分離開來,是以Nginx與PHP/PHP-FPM經常被部署在不同的伺服器上,以分擔前端Nginx伺服器的壓力,使Nginx專一處理靜态請求和轉發動态請求,而PHP/PHP-FPM伺服器專一解析PHP動态請求。

4、Nginx+PHP-FPM

      PHP-FPM是管理FastCGI的一個管理器,它作為PHP的插件存在,在安裝PHP要想使用PHP-FPM時在老php的老版本(php5.3.3之前)就需要把PHP-FPM以更新檔的形式安裝到PHP中,而且PHP要與PHP-FPM版本一緻,這是必須的)

   PHP-FPM其實是PHP源代碼的一個更新檔,旨在将FastCGI程序管理整合進PHP包中。必須将它patch到你的PHP源代碼中,在編譯安裝PHP後才可以使用。

   PHP5.3.3已經內建php-fpm了,不再是第三方的包了。PHP-FPM提供了更好的PHP程序管理方式,可以有效控制記憶體和程序、可以平滑重載PHP配置,比spawn-fcgi具有更多優點,是以被PHP官方收錄了。在./configure的時候帶 –enable-fpm參數即可開啟PHP-FPM。

      fastcgi已經在php5.3.5的core中了,不必在configure時添加 --enable-fastcgi了。老版本如php5.2的需要加此項。

      當我們安裝Nginx和PHP-FPM完後,配置資訊:

     PHP-FPM的預設配置php-fpm.conf:

     listen_address  127.0.0.1:9000 #這個表示php的fastcgi程序監聽的ip位址以及端口

      start_servers

      min_spare_servers

      max_spare_servers

      Nginx配置運作php: 編輯nginx.conf加入如下語句:

      location ~ \.php$ {

            root html;   

            fastcgi_pass 127.0.0.1:9000; 指定了fastcgi程序偵聽的端口,nginx就是通過這裡與php互動的

            fastcgi_index index.php;

            include fastcgi_params;

             fastcgi_param SCRIPT_FILENAME   /usr/local/nginx/html$fastcgi_script_name;

    }

    Nginx通過location指令,将所有以php為字尾的檔案都交給127.0.0.1:9000來處理,而這裡的IP位址和端口就是FastCGI程序監聽的IP位址和端口。

     其整體工作流程:

     1)、FastCGI程序管理器php-fpm自身初始化,啟動主程序php-fpm和啟動start_servers個CGI 子程序。

           主程序php-fpm主要是管理fastcgi子程序,監聽9000端口。

           fastcgi子程序等待來自Web Server的連接配接。

     2)、當用戶端請求到達Web Server Nginx是時,Nginx通過location指令,将所有以php為字尾的檔案都交給127.0.0.1:9000來處理,即Nginx通過location指令,将所有以php為字尾的檔案都交給127.0.0.1:9000來處理。

      3)FastCGI程序管理器PHP-FPM選擇并連接配接到一個子程序CGI解釋器。Web server将CGI環境變量和标準輸入發送到FastCGI子程序。

      4)、FastCGI子程序完成處理後将标準輸出和錯誤資訊從同一連接配接傳回Web Server。當FastCGI子程序關閉連接配接時,請求便告處理完成。

      5)、FastCGI子程序接着等待并處理來自FastCGI程序管理器(運作在 WebServer中)的下一個連接配接。

3.   Nginx的IO模型

     首先nginx支援的事件模型如下(nginx的wiki):

       Nginx支援如下處理連接配接的方法(I/O複用方法),這些方法可以通過use指令指定。

select – 标準方法。 如果目前平台沒有更有效的方法,它是編譯時預設的方法。你可以使用配置參數 –with-select_module 和 –without-select_module 來啟用或禁用這個子產品。

poll – 标準方法。 如果目前平台沒有更有效的方法,它是編譯時預設的方法。你可以使用配置參數 –with-poll_module 和 –without-poll_module 來啟用或禁用這個子產品。

kqueue – 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用雙處理器的MacOS X系統使用kqueue可能會造成核心崩潰。

epoll – 高效的方法,使用于Linux核心2.6版本及以後的系統。在某些發行版本中,如SuSE 8.2, 有讓2.4版本的核心支援epoll的更新檔。

rtsig – 可執行的實時信号,使用于Linux核心版本2.2.19以後的系統。預設情況下整個系統中不能出現大于1024個POSIX實時(排隊)信号。這種情況 對于高負載的伺服器來說是低效的;是以有必要通過調節核心參數 /proc/sys/kernel/rtsig-max 來增加隊列的大小。可是從Linux核心版本2.6.6-mm2開始, 這個參數就不再使用了,并且對于每個程序有一個獨立的信号隊列,這個隊列的大小可以用 RLIMIT_SIGPENDING 參數調節。當這個隊列過于擁塞,nginx就放棄它并且開始使用 poll 方法來處理連接配接直到恢複正常。

/dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.

eventport – 高效的方法,使用于 Solaris 10. 為了防止出現核心崩潰的問題, 有必要安裝這個 安全更新檔。

        在linux下面,隻有epoll是高效的方法

        下面再來看看epoll到底是如何高效的

       Epoll是Linux核心為處理大批量句柄而作了改進的poll。 要使用epoll隻需要這三個系統調用:epoll_create(2), epoll_ctl(2), epoll_wait(2)。它是在2.5.44核心中被引進的(epoll(4) is a new API introduced in Linux kernel 2.5.44),在2.6核心中得到廣泛應用。

        epoll的優點

支援一個程序打開大數目的socket描述符(FD)

        select 最不能忍受的是一個程序所打開的FD是有一定限制的,由FD_SETSIZE設定,預設值是2048。對于那些需要支援的上萬連接配接數目的IM伺服器來說顯 然太少了。這時候你一是可以選擇修改這個宏然後重新編譯核心,不過資料也同時指出這樣會帶來網絡效率的下降,二是可以選擇多程序的解決方案(傳統的 Apache方案),不過雖然linux上面建立程序的代價比較小,但仍舊是不可忽視的,加上程序間資料同步遠比不上線程間同步的高效,是以也不是一種完 美的方案。不過 epoll則沒有這個限制,它所支援的FD上限是最大可以打開檔案的數目,這個數字一般遠大于2048,舉個例子,在1GB記憶體的機器上大約是10萬左 右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統記憶體關系很大。

IO效率不随FD數目增加而線性下降

         傳統的select/poll另一個緻命弱點就是當你擁有一個很大的socket集合,不過由于網絡延時,任一時間隻有部分的socket是”活躍”的,但 是select/poll每次調用都會線性掃描全部的集合,導緻效率呈現線性下降。但是epoll不存在這個問題,它隻會對”活躍”的socket進行操 作—這是因為在核心實作中epoll是根據每個fd上面的callback函數實作的。那麼,隻有”活躍”的socket才會主動的去調用 callback函數,其他idle狀态socket則不會,在這點上,epoll實作了一個”僞”AIO,因為這時候推動力在os核心。在一些 benchmark中,如果所有的socket基本上都是活躍的—比如一個高速LAN環境,epoll并不比select/poll有什麼效率,相 反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模拟WAN環境,epoll的效率就遠在select/poll之上了。

使用mmap加速核心與使用者空間的消息傳遞。

        這 點實際上涉及到epoll的具體實作了。無論是select,poll還是epoll都需要核心把FD消息通知給使用者空間,如何避免不必要的記憶體拷貝就很 重要,在這點上,epoll是通過核心于使用者空間mmap同一塊記憶體實作的。而如果你想我一樣從2.5核心就關注epoll的話,一定不會忘記手工 mmap這一步的。

核心微調

         這一點其實不算epoll的優點了,而是整個linux平台的優點。也許你可以懷疑linux平台,但是你無法回避linux平台賦予你微調核心的能力。比如,核心TCP/IP協 議棧使用記憶體池管理sk_buff結構,那麼可以在運作時期動态調整這個記憶體pool(skb_head_pool)的大小— 通過echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函數的第2個參數(TCP完成3次握手 的資料包隊列長度),也可以根據你平台記憶體大小動态調整。更甚至在一個資料包面數目巨大但同時每個資料包本身大小卻很小的特殊系統上嘗試最新的NAPI網卡驅動架構。

    (epoll内容,參考epoll_互動百科)

4.   Nginx優化

1. 編譯安裝過程優化

1).減小Nginx編譯後的檔案大小

在編譯Nginx時,預設以debug模式進行,而在debug模式下會插入很多跟蹤和ASSERT之類的資訊,編譯完成後,一個Nginx要有好幾兆位元組。而在編譯前取消Nginx的debug模式,編譯完成後Nginx隻有幾百千位元組。是以可以在編譯之前,修改相關源碼,取消debug模式。具體方法如下:

在Nginx源碼檔案被解壓後,找到源碼目錄下的auto/cc/gcc檔案,在其中找到如下幾行:

# debug  

CFLAGS=”$CFLAGS -g” 

注釋掉或删掉這兩行,即可取消debug模式。

2.為特定的CPU指定CPU類型編譯優化

在編譯Nginx時,預設的GCC編譯參數是“-O”,要優化GCC編譯,可以使用以下兩個參數:

--with-cc-opt='-O3' 

--with-cpu-opt=CPU  #為特定的 CPU 編譯,有效的值包括:

pentium, pentiumpro, pentium3, # pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64 

要确定CPU類型,可以通過如下指令:

[root@localhost home]#cat /proc/cpuinfo | grep "model name" 

2. 利用TCMalloc優化Nginx的性能

TCMalloc的全稱為Thread-Caching Malloc,是谷歌開發的開源工具google-perftools中的一個成員。與标準的glibc庫的Malloc相比,TCMalloc庫在記憶體配置設定效率和速度上要高很多,這在很大程度上提高了伺服器在高并發情況下的性能,進而降低了系統的負載。下面簡單介紹如何為Nginx添加TCMalloc庫支援。

要安裝TCMalloc庫,需要安裝libunwind(32位作業系統不需要安裝)和google-perftools兩個軟體包,libunwind庫為基于64位CPU和作業系統的程式提供了基本函數調用鍊和函數調用寄存器功能。下面介紹利用TCMalloc優化Nginx的具體操作過程。

1).安裝libunwind庫

可以從http://download.savannah.gnu.org/releases/libunwind下載下傳相應的libunwind版本,這裡下載下傳的是libunwind-0.99-alpha.tar.gz。安裝過程如下:

[root@localhost home]#tar zxvf libunwind-0.99-alpha.tar.gz  

[root@localhost home]# cd libunwind-0.99-alpha/  

[root@localhost libunwind-0.99-alpha]#CFLAGS=-fPIC ./configure  

[root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC  

[root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC install 

2).安裝google-perftools

可以從http://google-perftools.googlecode.com下載下傳相應的google-perftools版本,這裡下載下傳的是google-perftools-1.8.tar.gz。安裝過程如下:

[root@localhost home]#tar zxvf google-perftools-1.8.tar.gz  

[root@localhost home]#cd google-perftools-1.8/  

[root@localhost google-perftools-1.8]# ./configure  

[root@localhost google-perftools-1.8]#make && make install  

[root@localhost google-perftools-1.8]#echo "/usr/

local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf  

[root@localhost google-perftools-1.8]# ldconfig 

至此,google-perftools安裝完成。

3).重新編譯Nginx

為了使Nginx支援google-perftools,需要在安裝過程中添加“–with-google_perftools_module”選項重新編譯Nginx。安裝代碼如下:

[[email protected]]#./configure \  

>--with-google_perftools_module --with-http_stub_status_module  --prefix=/opt/nginx  

[root@localhost nginx-0.7.65]#make  

[root@localhost nginx-0.7.65]#make install 

到這裡Nginx安裝完成。

4).為google-perftools添加線程目錄

建立一個線程目錄,這裡将檔案放在/tmp/tcmalloc下。操作如下:

[root@localhost home]#mkdir /tmp/tcmalloc  

[root@localhost home]#chmod 0777 /tmp/tcmalloc 

5).修改Nginx主配置檔案

修改nginx.conf檔案,在pid這行的下面添加如下代碼:

#pid        logs/nginx.pid;  

google_perftools_profiles /tmp/tcmalloc; 

接着,重新開機Nginx即可完成google-perftools的加載。

6).驗證運作狀态

為了驗證google-perftools已經正常加載,可通過如下指令檢視:

[root@ localhost home]# lsof -n | grep tcmalloc  

nginx      2395 nobody   9w  REG    8,8       0    1599440 /tmp/tcmalloc.2395  

nginx      2396 nobody   11w REG   8,8       0    1599443 /tmp/tcmalloc.2396  

nginx      2397 nobody   13w REG  8,8        0    1599441  /tmp/tcmalloc.2397  

nginx     2398 nobody    15w REG  8,8     0    1599442 /tmp/tcmalloc.2398 

由于在Nginx配置檔案中設定worker_processes的值為4,是以開啟了4個Nginx線程,每個線程會有一行記錄。每個線程檔案後面的數字值就是啟動的Nginx的pid值。

至此,利用TCMalloc優化Nginx的操作完成。

3.Nginx核心參數優化

核心參數的優化,主要是在Linux系統中針對Nginx應用而進行的系統核心參數優化。

下面給出一個優化執行個體以供參考。

net.ipv4.tcp_max_tw_buckets = 6000 

net.ipv4.ip_local_port_range = 1024 65000  

net.ipv4.tcp_tw_recycle = 1 

net.ipv4.tcp_tw_reuse = 1 

net.ipv4.tcp_syncookies = 1 

net.core.somaxconn = 262144 

net.core.netdev_max_backlog = 262144 

net.ipv4.tcp_max_orphans = 262144 

net.ipv4.tcp_max_syn_backlog = 262144 

net.ipv4.tcp_synack_retries = 1 

net.ipv4.tcp_syn_retries = 1 

net.ipv4.tcp_fin_timeout = 1 

net.ipv4.tcp_keepalive_time = 30 

将上面的核心參數值加入/etc/sysctl.conf檔案中,然後執行如下指令使之生效:

[root@ localhost home]#/sbin/sysctl -p 

下面對執行個體中選項的含義進行介紹:

net.ipv4.tcp_max_tw_buckets選項用來設定timewait的數量,預設是180 000,這裡設為6000。

net.ipv4.ip_local_port_range選項用來設定允許系統打開的端口範圍。

net.ipv4.tcp_tw_recycle選項用于設定啟用timewait快速回收。

net.ipv4.tcp_tw_reuse選項用于設定開啟重用,允許将TIME-WAIT sockets重新用于新的TCP連接配接。

net.ipv4.tcp_syncookies選項用于設定開啟SYN Cookies,當出現SYN等待隊列溢出時,啟用cookies進行處理。

net.core.somaxconn選項的預設值是128, 這個參數用于調節系統同時發起的tcp連接配接數,在高并發的請求中,預設的值可能會導緻連結逾時或者重傳,是以,需要結合并發請求數來調節此值。

net.core.netdev_max_backlog選項表示當每個網絡接口接收資料包的速率比核心處理這些包的速率快時,允許發送到隊列的資料包的最大數目。

net.ipv4.tcp_max_orphans選項用于設定系統中最多有多少個TCP套接字不被關聯到任何一個使用者檔案句柄上。如果超過這個數字,孤立連接配接将立即被複位并列印出警告資訊。這個限制隻是為了防止簡單的DoS攻擊。不能過分依靠這個限制甚至人為減小這個值,更多的情況下應該增加這個值。

net.ipv4.tcp_max_syn_backlog選項用于記錄那些尚未收到用戶端确認資訊的連接配接請求的最大值。對于有128MB記憶體的系統而言,此參數的預設值是1024,對小記憶體的系統則是128。

net.ipv4.tcp_synack_retries參數的值決定了核心放棄連接配接之前發送SYN+ACK包的數量。

net.ipv4.tcp_syn_retries選項表示在核心放棄建立連接配接之前發送SYN包的數量。

net.ipv4.tcp_fin_timeout選項決定了套接字保持在FIN-WAIT-2狀态的時間。預設值是60秒。正确設定這個值非常重要,有時即使一個負載很小的Web伺服器,也會出現大量的死套接字而産生記憶體溢出的風險。

如果發送端要求關閉套接字,net.ipv4.tcp_fin_timeout選項決定了套接字保持在FIN-WAIT-2狀态的時間。接收端可以出錯并永遠不關閉連接配接,甚至意外當機。

net.ipv4.tcp_fin_timeout的預設值是60秒。需要注意的是,即使一個負載很小的Web伺服器,也會出現因為大量的死套接字而産生記憶體溢出的風險。FIN-WAIT-2的危險性比FIN-WAIT-1要小,因為它最多隻能消耗1.5KB的記憶體,但是其生存期長些。

net.ipv4.tcp_keepalive_time選項表示當keepalive啟用的時候,TCP發送keepalive消息的頻度。預設值是2(機關是小時)。

4. PHP-FPM的優化

如果您高負載網站使用PHP-FPM管理FastCGI,這些技巧也許對您有用:

1)增加FastCGI程序數

把PHP FastCGI子程序數調到100或以上,在4G記憶體的伺服器上200就可以建議通過壓力測試擷取最佳值。

2)增加 PHP-FPM打開檔案描述符的限制

标簽rlimit_files用于設定PHP-FPM對打開檔案描述符的限制,預設值為1024。這個标簽的值必須和Linux核心打開檔案數關聯起來,例如,要将此值設定為65 535,就必須在Linux指令行執行“ulimit -HSn 65536”。

       然後 增加 PHP-FPM打開檔案描述符的限制:

     # vi /path/to/php-fpm.conf

    找到“<valuename="rlimit_files">1024</value>”

把1024更改為 4096或者更高.

重新開機 PHP-FPM.

         3)适當增加max_requests

    标簽max_requests指明了每個children最多處理多少個請求後便會被關閉,預設的設定是500。

    <value name="max_requests"> 500 </value>

5.   Nginx的php漏洞

漏洞介紹:nginx是一款高性能的web伺服器,使用非常廣泛,其不僅經常被用作反向代理,也可以非常好的支援PHP的運作。80sec發現其中存在一個較為嚴重的安全問題,預設情況下可能導緻伺服器錯誤的将任何類型的檔案以PHP的方式進行解析,這将導緻嚴重的安全問題,使得惡意的攻擊者可能攻陷支援php的nginx伺服器。

漏洞分析:nginx預設以cgi的方式支援php的運作,譬如在配置檔案當中可以以

location ~ .php$ {

root html;

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;

include fastcgi_params;

}

的方式支援對php的解析,location對請求進行選擇的時候會使用URI環境變量進行選擇,其中傳遞到後端Fastcgi的關鍵變量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name決定,而通過分析可以看到$fastcgi_script_name是直接由URI環境變量控制的,這裡就是産生問題的點。而為了較好的支援PATH_INFO的提取,在PHP的配置選項裡存在cgi.fix_pathinfo選項,其目的是為了從SCRIPT_FILENAME裡取出真正的腳本名。

那麼假設存在一個http://www.80sec.com/80sec.jpg,我們以如下的方式去通路

http://www.80sec.com/80sec.jpg/80sec.php

将會得到一個URI

/80sec.jpg/80sec.php

經過location指令,該請求将會交給後端的fastcgi處理,nginx為其設定環境變量SCRIPT_FILENAME,内容為

/scripts/80sec.jpg/80sec.php

而在其他的webserver如lighttpd當中,我們發現其中的SCRIPT_FILENAME被正确的設定為

/scripts/80sec.jpg

是以不存在此問題。

後端的fastcgi在接受到該選項時,會根據fix_pathinfo配置決定是否對SCRIPT_FILENAME進行額外的處理,一般情況下如果不對fix_pathinfo進行設定将影響使用PATH_INFO進行路由選擇的應用,是以該選項一般配置開啟。Php通過該選項之後将查找其中真正的腳本檔案名字,查找的方式也是檢視檔案是否存在,這個時候将分離出SCRIPT_FILENAME和PATH_INFO分别為

/scripts/80sec.jpg和80sec.php

最後,以/scripts/80sec.jpg作為此次請求需要執行的腳本,攻擊者就可以實作讓nginx以php來解析任何類型的檔案了。

POC: 通路一個nginx來支援php的站點,在一個任何資源的檔案如robots.txt後面加上/80sec.php,這個時候你可以看到如下的差別:

通路http://www.80sec.com/robots.txt

HTTP/1.1 200 OK

Server: nginx/0.6.32

Date: Thu, 20 May 2010 10:05:30 GMT

Content-Type: text/plain

Content-Length: 18

Last-Modified: Thu, 20 May 2010 06:26:34 GMT

Connection: keep-alive

Keep-Alive: timeout=20

Accept-Ranges: bytes

通路通路http://www.80sec.com/robots.txt/80sec.php

Date: Thu, 20 May 2010 10:06:49 GMT

Content-Type: text/html

Transfer-Encoding: chunked

X-Powered-By: PHP/5.2.6

其中的Content-Type的變化說明了後端負責解析的變化,該站點就可能存在漏洞。

漏洞廠商:http://www.nginx.org

解決方案:

我們已經嘗試聯系官方,但是此前你可以通過以下的方式來減少損失

關閉cgi.fix_pathinfo為0

或者

if ( $fastcgi_script_name ~ ..*/.*php ) {