nginx基本安全优化
隐藏nginx版本信息
现在许多漏洞扫描都是在根据软件版本针对性的进行渗透,如果我们可以不让软件版本公布于互联网,可以减少服务器被恶意渗透的概率,而nginx的隐藏自己的版本号也是很简单。
1 | ~]#curl -I 127.0.0.1 |
2 | HTTP/1.1 200 OK |
3 | Server: nginx/1.9.12 我们可以很轻松就得到nginx的版本号 |
4 | Date: Thu, 13 Apr 2017 05:19:56 GMT |
5 | Content-Type: text/html |
6 | Content-Length: 7 |
7 | Last-Modified: Sat, 25 Mar 2017 07:53:32 GMT |
8 | Connection: keep-alive |
9 | ETag: "58d621fc-7" |
10 | Accept-Ranges: bytes |
如果我们想要去掉这个版本号显示,可以在server端加入server_tokens参数:
1 | ~]#cat nginx.conf |
2 | http |
3 | { |
4 | ... |
5 | server_tokens off; |
6 | ... |
7 | } |
8 | |
9 | ~]#curl -I 127.0.0.1 |
10 | HTTP/1.1 200 OK |
11 | Server: nginx 这样就没有了nginx的版本号了 |
12 | Date: Thu, 13 Apr 2017 05:24:19 GMT |
13 | Content-Type: text/html |
14 | Content-Length: 7 |
15 | Last-Modified: Sat, 25 Mar 2017 07:53:32 GMT |
16 | Connection: keep-alive |
17 | ETag: "58d621fc-7" |
18 | Accept-Ranges: bytes |
掩藏nginx软件及版本号
虽然我们隐藏了版本号,但是只要是nginx显示着,恶意人员总可以进行猜测你的版本号是哪个版本之前的,并进行测试渗透,所以为了给黑客增加更大的难度,我们把原来的nginx也改掉。
nginx有在国内有两个比较流行的分支:tengine,openresty
所以这里我想把原生的nginx伪装成这两个分支,修改nginx的软件名,我们需要在未编译前修改源码包,然后重新编译。
依次修改3个nginx源码文件
nginx-1.9.12/src/core]#vim nginx.h
#define NGINX_VERSION “2.2.3”
#define NGINX_VER “openresty/“ NGINX_VERSION
#define NGINX_VAR “openresty”nginx-1.9.12/src/http]#vim ngx_http_header_filter_module.c
49 static char ngx_http_server_string[] = “Server: openresty” CRLF;nginx-1.9.12/src/http]#vim ngx_http_special_response.c
1
static u_char ngx_http_error_full_tail[] =
2
"<hr><center>" NGINX_VER "</center>" CRLF
3
"</body>" CRLF
4
"</html>" CRLF
5
;
6
7
8
static u_char ngx_http_error_tail[] =
9
"<hr><center>openresty</center>" CRLF
10
"</body>" CRLF
11
"</html>" CRLF
测试:
1
~]#curl -I 127.0.0.1
2
HTTP/1.1 200 OK
3
Server: openresty/2.2.3
4
Date: Thu, 13 Apr 2017 05:52:36 GMT
5
Content-Type: text/html
6
Content-Length: 612
7
Last-Modified: Thu, 13 Apr 2017 05:51:23 GMT
8
Connection: keep-alive
9
ETag: "58ef11db-264"
10
Accept-Ranges: bytes
更改nginx服务的默认用户
我们都清楚服务进程不得以root权限启动,虽然已root权限启动进程可以使我们配置起来相当便捷,但是这样的结果即是服务被劫持,黑客将获得的是最高服务器权限。
nginx修改worker进程属主数组有两种方法:
- 直接在编译的时候指明 –user=nginx –group=nginx
- 在nginx.conf中指明 user nginx nginx;
nginx创建建议 useradd -s /sbin/nologin -M nginx
根据参数优化nginx服务性能
优化worker进程个数
nginx采用的是master/worker的工作模式;master是为了管理worker进程,而真正工作的是worker进程。
worker进程个数,一般来说是服务器cpu的个数,多了也起不到任何效果,因为一个cpu在一个时间段只能完成一个任务。
查看cpu的核心数:
1 | ~]# grep -c processor /proc/cpuinfo |
2 | 2 |
3 | ~]# lscpu |
4 | ]#lscpu |
5 | Architecture: x86_64 |
6 | CPU op-mode(s): 32-bit, 64-bit |
7 | Byte Order: Little Endian |
8 | CPU(s): 2 |
9 | ... |
我们修改下nginx.conf的worker进程数。
1 | ~]# cat nginx.conf |
2 | ... |
3 | worker_processes 2; |
4 | ... |
5 | |
6 | 低版本不支持,近来的版本也支持auto选项。 |
7 | ~]# cat nginx.conf |
8 | ... |
9 | worker_processes auto; |
10 | ... |
auto选项也跟官方建议的一样,按照cpu个数来设定worker进程数,我设置的是auto,我们看下进程的个数:
1 | ]#ps aux | grep nginx |
2 | root 28542 0.0 0.0 45392 1880 ? Ss 13:52 0:00 nginx: master process ./nginx |
3 | nginx 28899 0.0 0.1 45812 1988 ? S 14:36 0:00 nginx: worker process |
4 | nginx 28900 0.0 0.1 45812 1988 ? S 14:36 0:00 nginx: worker process |
5 | root 28904 0.0 0.0 112648 972 pts/0 S+ 14:36 0:00 grep --color=auto nginx |
优化绑定nginx进程绑定到不同的cpu上
进程工作在哪个cpu上是内核分配的,这就会导致一个cpu很忙,一个cpu很闲,计算资源是宝贵的,为了保证cpu充分得到利用,我们可以调整worker进程绑定到不同的cpu上。
worker_cpu_affinity就是配置nginx进程与cpu亲和力的参数,即是把不同的进程分给不同的cpu上。
1 | ~]# cat nginx.conf |
2 | ... |
3 | worker_cpu_affinity 0001 0010; |
4 | ... |
nginx事物处理模型优化
httpd的MPM有三种模型,而nginx其实没什么可选择的,在linux下使用epoll的I/O多路复用模型,在Freebsd中使用kqueue的I/O多路复用模型,在solaris中使用/dev/poll方式I/O多路复用模型,在windows中使用icop。
1 | ~]#cat nginx.conf |
2 | ... |
3 | event { |
4 | ... |
5 | use epoll; |
6 | ... |
7 | } |
8 | ... |
对于nginx来说,支持的工作模式有select,poll,kqueue,epoll,rtsig和/dev/poll,其中select和poll都是标准的工作模式,kqueue和epoll是高效工作模式,在centos来说,推荐使用epoll,这是高性能高并发的设置。
调整nginx单个worker进程的最大连接数
worker_connection 的值根据具体服务器的性能和程序的内存使用情况来指定。
1 | ~]#cat nginx.conf |
2 | ... |
3 | event { |
4 | ... |
5 | worker_connections 20480; |
6 | ... |
7 | } |
8 | ... |
worker_connections用来设置一个worker process支持的最大并发连接数,这个连接包括所以连接,例如:代理服务器,客户端的连接等,实际并发连接数除了收worker_connections参数控制外,还和最大打开文件数worker_rlimit_nofile有关,nginx的总并发连接数=worker数量 x worker_connections。
调整nginx worker进程最大打开文件数
调整nginx打开的最大文件数,为什么说nginx的最大并发连接数还会受到这个参数的限制呢?因为每个打开的并发连接都是需要一个文件句柄的,当没有文件句柄的时候,这个连接也将无法建立。这里设置了worker进程可以打开最大的文件数,但是这个参数还受到系统打开最大文件数的限制,可以使用‘ulimit -HSn 65535’来临时设置系统打开的最大文件数。
1 | ~]#cat nginx.conf |
2 | ... |
3 | worker_rlimit_nofile 65535; |
4 | ... |
优化服务器域名散列表的大小
nginx的域名匹配规则,首先是精确匹配,再是左侧通配匹配,而后是右侧通配匹配,最后才是正则通配匹配。
如果定义了大量的域名或者定义太长的域名,我们需要调节http配置中的server_names_hash_max_size和server_names_hash_bucket_size的值。
如果定义了太长的域名会出现:
1 | could not build the server_names_hash, |
2 | you should increase server_names_hash_bucket_size: 32 |
出现这样的情况我们需要增加server_names_hash_bucket_size的值。
如果定义了太多的域名,会得到一个另一个错误信息:
1 | could not build the server_names_hash, |
2 | you should increase either server_name_hash_max_size: 512 |
3 | or server_names_hash_bucket_size: 32 |
首先增加server_names_hash_max_size;如果启动不了,或者启动缓慢,则再增加server_names_names_hash_bucket_size的值。
开启高效文件传输模式
sendfile参数开启文件高效传输模式,简单来说就是在内核空间直接构建响应报文,而不通过用户空间构建再返回到内核空间在通过内核tcp协议栈发送给客户端。
sendfile打开的同时也打开了tcp_nopush和tcp_nodelay的功能,可以防止网络或磁盘的I/O堵塞,提升nginx的效率。
1 | sendfile on; |
2 | tcp_nopush on; |
3 | tcp_nodelay on; |
tcp_nopush作用是将http的响应报文的头部信息和文件的开始部分发在一个文件中发布,可以减少网络报文段的数量。
tcp_nodelay作用是当数据发送的时候,内核并不会立刻发送,需要等待更多的字节组成一个数据包,这样可以提高网络I/O的性能,但是业务数据较少的时候的启用tcp_nodelay可能会导致等待时间过长。
优化nginx连接超时时间
nginx连接超时设置keepalive_timeout是为了保持持久连接的参数,有利有弊,当访问量较少的时候,这个参数的设置是可以较少服务开销,加快访问数据的,而当访问量巨大的时候,这个参数设置的过大,则会导致新连接等待,因为一个nginx的访问量是有限的,旧连接不退出,新连接就不会建立。
1 | keepalive_timeout 65s;[default 75s] |
client_header_timeout 此处可以设置为15s,默认是60s,设置这个值的好处是,客户端发送请求报文头部,如果15s还没发完请求头部,服务器就返回‘Request time out(408)’错误,设置个超时值,可以防止客户端理由http协议进行攻击。
client_body_timeout 用于读取客户端请求主体的超时时间,默认60s,这个参数是两次成功读取请求操作之间的一个超时,而不是读取整个主体的超时时间。
send_timeout 用于指定客户端在这个时间端内,客户端没有任何活动,nginx就关闭连接,默认60s。
上传文件的大小限制
client_max_body_size 8m; 默认1m,一般情况下只有post方法在提交数据时才会携带请求信息。
设置这个值允许最大客户端请求主体大小,在请求头域有‘Content-Length’,如果超过了此配置值,客户端会收到一个413错误,意思请求条目过大,设置0表示禁止检查客户端请求主体大小,此参数对提高服务器安有一定作用。
Fastcgi参数优化
首先我们需要知道整个LNMP的结构,我们才可以对fastcgi的配置进行优化。
- fastcgi_connect_timeout:表示nginx服务器与fastcgi服务器连接的超时时间,默认60秒。
- fastcgi_send_timeout:设置nginx允许fastcgi服务器端返回的数据超时时间,即在规定时间内后端服务器必须传完所以数据,默认值60秒。
- fastcgi_read_timeout:设置nginx允许fastcgi服务器端读取响应信息的超时时间,表示连接成功后,nginx等待后端服务器响应的时间。
- fastcgi_buffer_size:这是nginx fastcgi的缓冲区大小的参数,设定用来读取从fastcgi服务器端收到的第一部分响应信息的缓冲区大小,这个参数由fastcgi_buffers来指定一个缓冲区大小。
- fastcgi_buffers:指定本地需要多少或多大的缓冲区来缓冲fastcgi的应答请求,指定方式 4 64k这样的格式。
- proxy_busy_buffers_size:用于系统繁忙时proxy_buffers的大小。
- fastcgi_busy_buffers_size:用于设定系统繁忙时fastcgi_buffers的大小。
- fastcgi_temp_file_write_size:fastcgi临时文件的大小。
- fastcgi_cache zone | off:是否启用cache,如果启用,数据缓存于哪个cache中
- fastcgi_cache_key string:定义要使用的缓存键
- fastcgi_cache_method GET | HEAD | POST …:缓存哪些类型的请求的相关数据
- fastcgi_cache_min_user number:表示请求几次后被缓存
- fastcgi_cache_vaild [code…] time:定义对不同响应码设置不同缓存时间
- fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
path:文件系统路径,用于存储缓存的文件数据
max_size=size: 定义此路径下的多大空间用于存储管理
levels=#[:#[:#]]:缓存目录层级定义 levels=1:2
keys_zone=name:size:内存中用于缓存k/v映射关系的空间名称及大小
inactive=time
注意调用缓存时,至少应该指定三个参数:
- fastcgi_cache
- fastcgi_cache_key
- fastcgi_cache_vaild
gzip压缩实现性能优化
nginx gzip提供了压缩文件内容的功能,需不需要压缩也需要看对象:
- 纯文本文件压缩比高,因此纯文本最好都压缩,例如:html,js,css,xml,shtml等格式的文件。
- 被压缩的纯文本文件必须大于1kb,由于压缩算法的缘故,极小的文件压缩kennel会更大。
- 图片,视频等文件不要压缩,因为这些文件一般都是经过压缩的,压缩不了多少,而且浪费cpu和内存。
压缩配置参数:
1 | gzip on; |
2 | 开启gzip压缩 |
3 | gzip_min_length 1k; |
4 | 设置允许压缩的页面最小字节数 |
5 | gzip_buffers 4 16k; |
6 | 压缩缓冲区大小 |
7 | gzip_http_version 1.1; |
8 | 压缩http版本 |
9 | gzip_comp_level 9; |
10 | 压缩比率 |
11 | gzip_types text/html text/javascript text/xml text/css application/x-javascript; |
12 | 指定压缩的mine的类型 |
expires缓存实行性能优化
网站中css,js,图片等网站元素更改的机会很少,会使客户的浏览器本地缓存下这些数据,而后下次打开的时候不需要重写下载这些元素。
配置实例:
1 | location ~ .*\.(gif|png|jpeg|swf) { |
2 | expires 365d; |
3 | } |
网站防止盗链
网站中资源被外部网站恶意盗用,如果正在使用cdn,这些资源被频繁的使用,也是一笔不小的流量费。
定义合法的引用
vaild_referers none | blocked | server_name | string …
定义合法的referer数据
none:请求报文的首部没有referer首部
blocked:请求报文的referer首部没有值
server_names: 其值是主机名
arbitrary string: 直接字符串,可以使用*作为通配符
regular expression:被指定的正则的表达式模式匹配到的字符串;要使用~开头
if($invaild_referer)
return 403
}
nginx防爬虫优化
Roboot协议(也称爬虫协议,机器人协议),网站通过Roboot协议告诉搜索引擎哪些可以被爬取,哪些不可以被爬取。
如我们可以看下淘宝的reboot协议: www.taobao.com/robots.txt
爬虫优化配置,我们可以通过$http_user_agent来指定爬虫:
1 | if ($http_user_agent ~* "baiduspider|googlebot|sougou web spider") { |
2 | return 403; |
3 | } |
控制nginx并发连接数量
- limit_conn_zone参数
语法:limit_conn_zone key zone=name:size
用于设置共享内存空间,key可以是字符串,nginx自带变量$binary_remote_addr,$server_name。 - limit_conn zone number;
用于指定key设置最大连接数,当超过最大连接数,返回503.
限制单ip的最大连接数:
1 | http { |
2 | ... |
3 | limit_conn_zone $binary_remote_addr zone=addr:zone; |
4 | ... |
5 | } |
6 | |
7 | location { |
8 | limit_conn addr 1; 限制单ip的并发连接数为1 |
9 | |
10 | } |