Nginx工作原理和优化、漏洞(下)

来源:huangguisu

链接:http://blog.csdn.net/hguisu/article/details/8930668


6.   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。安装代码如下:

 

[root@localhostnginx-0.7.65]#./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_syn_retries选项表示在内核放弃建立连接之前发送SYN包的数量。

如果发送端要求关闭套接字,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

找到“1024”

把1024更改为 4096或者更高.

重启 PHP-FPM.

 

ulimit -n 要调整为65536甚至更大。如何调这个参数,可以参考网上的一些文章。命令行下执行 ulimit -n 65536即可修改。如果不能修改,需要设置  /etc/security/limits.conf,加入

 

* hard nofile65536

* soft nofile 65536

 

3)适当增加max_requests

 

标签max_requests指明了每个children最多处理多少个请求后便会被关闭,默认的设置是500。

 

500

4.nginx.conf的参数优化

 

nginx要开启的进程数 一般等于cpu的总核数 其实一般情况下开4个或8个就可以。

 

每个nginx进程消耗的内存10兆的模样

 

worker_cpu_affinity

仅适用于linux,使用该选项可以绑定worker进程和CPU(2.4内核的机器用不了)

 

假如是8 cpu 分配如下:
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000

00100000 01000000 10000000

 

nginx可以使用多个worker进程,原因如下:

 

to use SMP
to decrease latency when workers blockend on disk I/O
to limit number of connections per process when select()/poll() is

used The worker_processes and worker_connections from the event sections

allows you to calculate maxclients value: k max_clients = worker_processes * worker_connections

worker_rlimit_nofile 102400;

 

每个nginx进程打开文件描述符最大数目 配置要和系统的单进程打开文件数一致,linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535 nginx调度时分配请求到进程并不是那么的均衡,假如超过会返回502错误。我这里写的大一点

 

use epoll

 

Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。

 

处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。在高并发服务器中,轮询I/O是最耗时间的操作 目前Linux下能够承受高并发

访问的Squid、Memcached都采用的是epoll网络I/O模型。

 

worker_connections 65535;
每个工作进程允许最大的同时连接数 (Maxclient = work_processes * worker_connections)

keepalive_timeout 75

keepalive超时时间

 

这里需要注意官方的一句话:
The parameters can differ from each other. Line Keep-Alive:

timeout=time understands Mozilla and Konqueror. MSIE itself shuts

keep-alive connection approximately after 60 seconds.

client_header_buffer_size 16k
large_client_header_buffers 4 32k

客户请求头缓冲大小
nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取

如果设置过小HTTP头/Cookie过大 会报400 错误 nginx 400 bad request
求行如果超过buffer,就会报HTTP 414错误(URI Too Long) nginx接受最长的HTTP头部大小必须比其中一个buffer大,否则就会报400的HTTP错误(Bad Request)。

 

open_file_cache max 102400

 

使用字段:http, server, location 这个指令指定缓存是否启用,如果启用,将记录文件以下信息: ·打开的文件描述符,大小信息和修改时间. ·存在的目录信息. ·在搜索文件过程中的错误信息 — 没有这个文件,无法正确读取,参考open_file_cache_errors 指令选项:
·max – 指定缓存的最大数目,如果缓存溢出,最长使用过的文件(LRU)将被移除
例:

 

open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;

open_file_cache_errors

语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.

 

open_file_cache_min_uses

 

语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如 果使用更大的值,文件描述符在cache中总是打开状态.
open_file_cache_valid

 

语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息.
开启gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css

application/xml;
gzip_vary on;

 

缓存静态文件:

 

location ~* ^.+.(swf|gif|png|jpg|js|css)$ {

root /usr/local/ku6/ktv/show.ku6.com/;

expires 1m;

}

 

7.   错误排查

 

1、Nginx 502 Bad Gateway

 

php-cgi进程数不够用、php执行时间长(mysql慢)、或者是php-cgi进程死掉,都会出现502错误

 

一般来说Nginx 502 Bad Gateway和php-fpm.conf的设置有关,而Nginx 504 Gateway Time-out则是与nginx.conf的设置有关

 

1)、查看当前的PHP FastCGI进程数是否够用:

 

netstat -anpo | grep “php-cgi” | wc -l

 

如果实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么,说明“FastCGI进程数”不够用,需要增大。

 

2)、部分PHP程序的执行时间超过了Nginx的等待时间,可以适当增加

nginx.conf配置文件中FastCGI的timeout时间,例如:

 

http {

......

fastcgi_connect_timeout 300;

fastcgi_send_timeout 300;

fastcgi_read_timeout 300;

......

}

 

2、413 Request Entity Too Large
解决:增大client_max_body_size

 

client_max_body_size:指令指定允许客户端连接的最大请求实体大小,它出现在请求头部的Content-Length字段. 如果请求大于指定的值,客户端将收到一个”Request Entity Too Large” (413)错误. 记住,浏览器并不知道怎样显示这个错误.

 

php.ini中增大
post_max_size 和upload_max_filesize

 

3 Ngnix error.log出现:

 

upstream sent too big header while reading response header from upstream错误

 

1)如果是nginx反向代理

proxy是nginx作为client转发时使用的,如果header过大,超出了默认的1k,就会引发上述的upstream sent too big header (说白了就是nginx把外部请求给后端server,后端server返回的header  太大nginx处理不过来就导致了。

 

server {

listen       80;

server_name  *.xywy.com ;

 

large_client_header_buffers 4 16k;

 

location / {

 

#添加这3行

proxy_buffer_size 64k;

proxy_buffers   32 32k;

proxy_busy_buffers_size 128k;

 

proxy_set_header Host $host;

proxy_set_header X-Real-IP       $remote_addr;

proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;

 

}

 

}

 

2)如果是 nginx+PHPcgi

 

错误带有 upstream: “fastcgi://127.0.0.1:9000″。就该

 

多加:

 

fastcgi_buffer_size 128k;

fastcgi_buffers 4 128k;

 

server {

listen       80;

server_name  ddd.com;

index index.html index.htm index.php;

 

client_header_buffer_size 128k;

large_client_header_buffers 4 128k;

proxy_buffer_size 64k;

proxy_buffers 8 64k;

fastcgi_buffer_size 128k;

fastcgi_buffers 4 128k;

 

location / {

 

......

 

}

 

}

 

8.   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

 

HTTP/1.1 200 OK

Server: nginx/0.6.32

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

Content-Type: text/html

Transfer-Encoding: chunked

Connection: keep-alive

Keep-Alive: timeout=20

X-Powered-By: PHP/5.2.6

 

其中的Content-Type的变化说明了后端负责解析的变化,该站点就可能存在漏洞。

 

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

 

解决方案:

 

我们已经尝试联系官方,但是此前你可以通过以下的方式来减少损失

关闭cgi.fix_pathinfo为0

或者

 

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

return 403;

}

 

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓