Nginx 安全优化
隐藏Nginx版本号
1 | http |
Nginx更改默认用户
nginx配置中指定用户启动
1 | $ vim /etc/nginx/nginx.conf |
优化Nginx服务性能
Nginx指定进程数
worker_processes语法:
1 | syntax: worker_processes number; #此行为参数语法,number为数量 |
优化Nginx进程个数的策略:
worker进程数最开始的设置可以等于CPU的核数,且worker进程数要多一些,这样起始提供服务时就不会出现因为访问量快速增加而临时启动新进程提供服务的问题,缩短了系统的瞬时开销和提供服务的时间,提升了服务用户的速度。高流量高并发场合也可以考虑将进程数提高至CPU核数*2,具体情况要根据实际的业务来选择,因为这个参数除了要和CPU核数匹配外,也和硬盘存储的数据及系统的负载有关,设置为CPU的核数是一个好的起始配置,这也是官方的建议。
Nginx 进程优化
默认情况下,Nginx的多个进程有可能跑在某一个CPU或CPU的某一核上,导致Nginx进程使用硬件的资源不均,本节的优化是尽可能地分配不同的Nginx进程给不同的CPU处理,达到充分有效利用硬件的多CPU多核资源的目的。
在优化不同的Nginx进程对应不同的CPU配置时,四核CPU服务器的参数配置参考如下:
1 | worker_processes 4; |
四核和八核CPU服务器的参数配置参考如下:
1 | # 八核掩码 |
下面是绑定的实例配置:
1 | worker_processes 4; |
Nginx 事件模型优化
Nginx的连接处理机制在不同的操作系统会采用不同的I/O模型,在Linux下,Nginx使用epoll的I/O多路复用模型,在Freebsd中使用kqueue的I/O多路复用模型,在Solaris中使用/dev/poll方式的I/O多路复用模型,在Windows中使用的是icop,等等。要根据系统类型选择不同的事件处理模型,可供使用的选择有“use [kqueue|rtsig|epoll|/dev/poll|select|poll];”。
事件模型语法:
1 | synstax: use method; # 络模型配置,method选择模型之一 |
实践修改Nginx配置:
1 | $ vi /etc/nginx/nginx.conf |
根据Nginx官方文档建议,也可以不指定事件处理模型,Nginx会自动选择最佳的事件处理模型服务。
Nginx 最大连接数
调整Nginx单个进程允许的客户端最大连接数,这个控制连接数的参数为work_connections,worker_connections的值要根据具体服务器性能和程序的内存使用量来指定(一个进程启动使用的内存根据程序确定)
worker_connections语法:
1 | synstax: worker_connections number |
实践修改Nginx配置:
1 | $ vi /etc/nginx/nginx.conf |
说明:
worker_connections用来设置一个worker process支持的最大并发连接数,这个连接数包括了所有链接,例如:代理服务器的连接,客户端的连接等,实际的并发连接数除了受worker_connections参数控制外,还和最大打开文件数worker_rlimit_nofile有关(见下文),Nginx总并发连接=worker数量*worker_connections。
参考资料:http://nginx.org/en/docs/ngx_core_module.html
Nginx 文件描述符
调整配置Nginx worker进程的最大打开文件数,这个控制连接数的参数为worker_rlimit_nofile。
worker_rlimit_nofile语法:
1 | synstax: worker_rlimit_nofile number |
实践修改Nginx配置:
1 | $ vi /etc/nginx/nginx.conf |
Nginx高效传输
设置参数:sendfile on;
sendfile参数用于开启文件的高效传输模式。同时将tcp_nopush和tcp_nodelay两个指令设置为on,可防止网络及磁盘I/O阻塞,提升Nginx工作效率。
参数作用:激活或禁用sendfile()功能功能。sendfile()是作用于两个文件描述符之间的数据拷贝函数,这个拷贝操作是在内核之中的,被称为“零拷贝”,sendfile()比read和write函数要高效很多,因为,read和write函数要把数据拷贝到应用层再进行操作。相关控制参数还有sendfile_max_chunk。
参考资料:http://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile
设置参数:tcp_nopush on;
提高网络的“传输效率”
参数作用:激活或禁用Linux上的TCP_CORK socket选项,此选项仅仅当开启sendfile时才生效,激活这个tcp_nopush参数,数据包不会马上转发出去,而是等数据包最大时,一次性转发出去,有效解决网络堵塞。
参考资料:http://nginx.org/en/docs/http/ngx_http_core_module.html
设置参数:tcp_nodelay on;
在keeplive连接下,提高网络的传输“实时性”
用于激活tcp_ondelay功能,提高I/O性能。
参数作用:默认情况下当数据发送时,内核并不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高I/O性能。但是,在每次只发送很少字节的业务场景中,使用 tcp_nodelay功能能够让数据包立刻转发出去。
参数生效条件:
激活或禁用TCP_NODELAY选项,当一个连接进入keep-alive状态时生效。
参考资料:http://nginx.org/en/docs/http/ngx_http_core_module.html
Nginx连接参数优化
keepalive_timeout
用于设置客户端连接保持会话的超时时间为60秒。超过这个时间,服务器会关闭该连接,此数值为参考值。
参数作用:keep-alive可以使客户端到服务器端已经建立的连接一直工作不退出,当服务器有持续请求时,keep-alive会使用已经建立的连接提供服务,从而避免服务器重新建立新连接处理请求。
此参数设置一个keep-alive(客户端连接在服务器端保持多久后退出),其单位是秒,和HTTP响应header域的“Keep-Alive:timeout=time”参数有关,这些header信息也会被客户端浏览器识别并处理,不过有些客户端并不能按照服务器端的设置来处理,例如:MSIE大约60秒后会关闭keep-alive连接。
参考资料:http://nginx.org/en/docs/http/ngx_http_core_module.html
client_header_timeout
用于设置读取客户端请求头数据的超时时间。此处的数值15,其单位是秒,为经验参考值。
参数作用:设置读取客户端请求头数据的超时时间。如果超过这个时间,客户端还没有发送完整的header数据,服务器端将返回“Request time out (408)”错误,可指定一个超时时间,防止客户端利用http协议进行攻击。
参考资料:http://nginx.org/en/docs/http/ngx_http_core_module.html
client_body_timeout
用于设置读取客户端请求主体的超时时间,默认值60
参数作用:设置读取客户端请求主体的超时时间。这个超时仅仅为两次成功的读取操作之间的一个超时,非请求整个主体数据的超时时间,如果在这个超时时间内,客户端没有发送任何数据,Nginx将返回“Request time out(408)”错误,默认值60,
send_timeout 25
用于指定响应客户端的超时时间。这个超时仅限于两个连接活动之间的时间,如果超过这个时间,客户端没有任何活动或者Nginx数据没有发送完,Nginx都将会关闭连接,默认值为60秒,可以改为参考值25秒。
参数作用:设置服务器端发送HTTP响应信息到客户端的超时时间,这个超时仅仅为两次成功握手后的一个超时,非请求整个响应数据的超时时间,如在这个超时时间内,客户端没有接收任何数据,连接将被关闭。
Nginx上传文件大小限制
参数作用:设置最大的允许的客户端请求主体大小,在请求头域有“Content-Length”,如果超过了此配置值,客户端会受到413错误,意思是请求的条目过大,有可能浏览器不能正确显示。设置为0表示禁止检查客户端请求主体大小。此参数对提高服务器端的安全性有一定作用。
FastCGI调优
FastCGI参数是配合Nginx向后请求PHP动态引擎服务的相关参数。
FastCGI常见参数的Nginx配置示例如下:
1 | $ cat /etc/nginx/nginx.conf |
Nginx gzip
Nginx gzip压缩模块提供了压缩文件内容的功能,用户请求的内容在发送到用户客户端之前,Nginx服务器会根据一些具体的策略实施压缩,以节约网站出口带宽,同时加快数据传输效率,来提升用户访问体验。
Nginx gzip压缩的优点
1.提升网站用户体验:发送给用户的内容小了,用户访问单位大小的页面就加快了,用户体验提升了,网站口碑就好了。
2.节约网站带宽成本:数据是压缩传输的,因此节省了网站的带宽流量成本,不过压缩时会稍微消耗一些CPU资源,这个一般可以忽略。
对应的压缩参数说明如下:
1 | #压缩配置 |
Nginx Expires 缓存
简单说,Nginx expires的功能就是为用户访问的网站内容设定一个过期时间,当用户第一次访问这些内容时,会把这些内容存储在用户浏览器本地,这样用户第二次及以后继续访问该网站时,浏览器会检查加载已经缓存在用户浏览器本地的内容,就不会去服务器请求了,当缓存的内容过期了会向源服务器发送请求,检查缓存内容是否被修改。
更深入的理解:
expires的功能就是允许通过Nginx配置文件控制HTTP的“Expires”和“Cache-Control”响应头部内容,告诉客户端浏览器是否缓存和缓存多久以内访问的内容。这个expires模块控制Nginx服务器应答时的expires头内容和Cache-Control头的max-age指令。缓存的有效期可以设置为相对于源文件的最后修改时刻或客户端的访问时刻。
这些HTTP头向客户端表明了额内容的有效性和持久性。如果客户端本地有内容缓存,则内容就可以从缓存而不是从服务器中读取,然后客户端会检查缓存中的副本,看其是否过期或失效,以决定是否重新从服务器获得内容更新。
Nginx expires配置详解
根据文件扩展名进行判断,添加expires功能范例
1 | location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ |
1 | location ~ .*\.(js|css)$ |
根据URL中的路径(目录)进行判断,添加expires功能范例
1 | location ~ ^/(images|javascript|js|css|flash|media|static)/ |
注意事项:expires只能在web节点上的nginx的配置文件里生效,如果配置在nginx方向代理的话,expires是不生效的
Nginx 日志文件安全
不记录特定的访问日志
在实际工作中,对于负载均衡器健康节点检查或某些特定文件(比如图片,JS,CSS)的日志,一般不需要记录下来,因为在统计PV时是按照页面计算的,而且日志写入太频繁会消耗大量磁盘I/O,降低服务的性能。
1 | location ~ .*\.(js|jpg|JPG|jpeg|JPEG|css|bmp|gif|GIF)$ { |
访问日志的权限设置
假如日志目录为/app/logs,则授权方法如下:
1 | chown -R root.root /app/logs |
不需要在日志目录上给Nginx用户读或写许可,但很多网友都没注意这个问题,他们把该权限直接给了Nginx或Apache用户,这就成为了安全隐患。
Nginx 访问控制
根据扩展名限制程序和文件访问
1 | location ~ ^/images/.*\.(php|php5|sh|pl|py)$ { |
对上述目录的限制必须写在Nginx处理PHP服务配置的前面,如下:
1 | location ~ .*\.(php|php5)$ |
Nginx下配置禁止访问.txt和.doc文件
1 | location ~* \.(txt|doc)$ |
禁止访问指定的目录
1 | #禁止访问单个目录的命令如下: |
1 | #禁止访问目录并返回指定的HTTP状态码 |
Nginx 限制来源IP访问
使用ngx_http_access_module限制网站来源IP访问
1 | # 禁止某目录让外界访问,但允许某IP访问该目录,且支持PHP解析,命令如下: |
Nginx做反向代理的时候可以限制客户端IP
1 | #方法一:使用if来控制,命令如下: |
注意事项:
1.deny一定要加一个IP,否则会直接跳转到403,不再往下执行了,如果403默认页是在同一域名下,会造成死循环访问。
2.对于allow的IP段,从允许访问的段位从小到大排列,如127.0.0.0/24的下面才能是10.10.0.0/16,其中:
1)24表示子网掩码:255.255.255.0
2)16表示子网掩码:255.255.0.0
3)8表示子网掩码:255.0.0.0
3.以deny all:结尾,表示除了上面允许的,其他的都禁止。如:
1)deny 192.168.1.1;
2)allow 127.0.0.0/24;
3)allow 192.168.0.0/16;
4)allow 10.10.0.0/16;
5)deny all;
Nginx 禁止非法域名解析
Nginx如何防止用户IP访问网站(恶意域名解析,也相当于是直接IP访问企业网站)
1 | # 方法一 |
Nginx 防爬虫
我们可以根据客户端的user-agents信息,轻松地阻止指定的爬虫爬取我们的网站。下面来看几个案例。
1 | # 阻止下载协议代理 |
Nginx 限制HTTP请求方法
最常用的HTTP方法为GET,POST,我们可以通过Nginx限制HTTP请求的方法来达到提升服务器安全的目的,例如,让HTTP只能使用GET,HEAD和POST方法的配置如下:
1 | #Only allow these request methods |
当上传服务器上传数据到存储服务器时,用户上传写入的目录就不得不给Nginx对应的用户相关权限,这样一旦程序有漏洞,木马就有可能被上传到服务器挂载的对应存储服务器的目录里,虽然我们也做了禁止PHP,SH,PL,PY等扩展名的解析限制,但还是会遗漏一些想不到的可执行文件。对于这样情况,该怎么办呢?事实上,还可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入。
例如,在上传服务器上限制HTTP的GET方法的配置如下:
1 | #Only deny GET request methods ## |
Nginx 连接限制
连接频率限制 limit_conn_module
请求频率限制 limit_req_module
Nginx连接限制配置
具体配置如下:
1 | http { #http段配置连接限制, 同⼀时刻只允许⼀个客户端IP连接 |
Nginx 请求限制配置
具体配置如下:
1 | http { ##http段配置请求限制, rate限制速率,限制⼀秒钟最多⼀个IP请求 |
Nginx SSL HTTPS
开启 HTTP/2
HTTP/2最初是在Nginx版本1.9.5中实现的,以取代spdy。在Nginx上启用HTTP/2模块很简单。
原先的配置:
1 | listen 443 ssl; |
修改为:
1 | listen 443 ssl http2; |
可以通过curl来验证:
1 | curl --http2 -I https://domain.com/ |
开启 SSL session 缓存
启用 SSL Session 缓存可以减少 TLS 的反复验证,减少 TLS 握手。 1M 的内存就可以缓存 4000 个连接,非常划算,现在内存便宜,尽量开启。
1 | ssl_session_cache shared:SSL:50m; # 1m 4000个, |
禁用 SSL session tickets
由于Nginx中尚未实现SSL session tickets,可以关闭。
1 | ssl_session_tickets off; |
禁用 TLS version 1.0
1 | ssl_protocols TLSv1.2 TLSv1.3; |
启用OCSP Stapling
如果不启用 OCSP Stapling 的话,在用户连接你的服务器的时候,需要去验证证书,这个验证证书的时间不可控,我们开启OCSP Stapling后,可以省掉这一步。
1 | ssl_stapling on; |
减小ssl buffer size
ssl_buffer_size 控制在发送数据时的 buffer 大小,默认情况下,缓冲区设置为16k,为了最大程度地减少TTFB(至第一个字节的时间),最好使用较小的值,这样TTFB可以节省大约30 – 50ms。
1 | ssl_buffer_size 4k; |
调整 Cipher 优先级
更新更快的 Cipher放前面,这样延迟更小。
1 | # 手动启用 cipher 列表 |