增强Nginx的SSL安全性和性能

你的站点启用https了吗?如果启用了,其安全性如何呢?

到站长工具:

http://s.tool.chinaz.com/https/

 

输入网址检测一下,就可以看到报告:

增强Nginx的SSL安全性和性能_第1张图片

以上这个结果说明基本OK。

 

报告下方有个配置指南,配置指南里有提到两点:

1. 需要配置符合PFS规范的加密套件,推荐配置:

ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;

2. 需要在服务端TLS协议中启用TLS1.2,推荐配置:

TLSv1 TLSv1.1 TLSv1.2。

我们就这两点对Nginx配置进行调整如下,增加了红色的几行:

    server {
        listen 443 ssl;
        server_name dancen.com www.dancen.com;
        access_log off;
        root /home/site/dancen;
        ssl_certificate /etc/letsencrypt/live/dancen.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/dancen.com/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
		ssl_prefer_server_ciphers on;
		ssl_session_cache shared:SSL:10m;
		ssl_session_timeout 30m;

        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;		
    }

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

Context:    http, server

这里所做的,就是关闭SSLv2和SSLv3这些古董协议,使用TLSv1 TLSv1.1 TLSv1.2这几个新一点的安全协议,你甚至可以只使用TLSv1.2,TLSv1.3。安全协议这东西,通常越新越安全,但太新的协议,和一些较老的前端可能就会存在兼容问题。

 

ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;

这里使用了推荐的加密套件,排除了安全性不佳、性能低下的加密算法。加密套件的顺序是非常重要的,因为其决定了优先选择哪个算法。

 

ssl_prefer_server_ciphers on;

设置协商加密算法时,优先使用我们服务端的加密套件,而不是客户端浏览器的加密套件。如果只配置了加密套件,而未设置此项,加密套件的设定就没有意义了。

 

ssl_session_cache shared:SSL:10m;

设置ssl/tls会话缓存的类型和大小。启用https后,会加剧服务器的负担。传统的http使用TCP三次握手建立连接,而SSL和TLS在这个基础上还需要9个握手包,所以这个负担显而易见,可以通过重用Session提高https的性能。

设置存储session参数的缓存的类型和大小。缓存可以是下面任何一种类型:

off

严格禁止使用会话缓存:nginx明确告知客户端会话不可重用。

none

会话缓存是不允许的:nginx告知客户端会话可以重用,但并没有在缓存中存储会话参数。

builtin

在OpenSSL中构建缓存;只能被一个工作进程使用。缓存的大小在会话中指定,如果没有指定大小,默认20480个会话。使用内置缓存会导致内存碎片化。

shared

缓存在所有工作进程之间共享。缓存大小按照字节为单位指定;1MB可以存储4000个会话。每块共享内存都应该起个名字。同一块缓存可以在多个虚拟服务中使用。

 

两种类型的缓存可以同时使用:

ssl_session_cache builtin:1000 shared:SSL:10m;

 

但是,单独使用共享缓存会更有效。这个参数默认是none,和off差不多,停用缓存。我们的设置是shared,因为buildin可能会产生内存碎片,如shared:SSL:10m表示我所有的nginx工作进程共享10m的SSL会话缓存。

 

ssl_session_timeout 30m;

指定客户端可以重用会话参数的时间(超时后不可使用),默认值是5m,即5分钟。

 

其他设置

keepalive_timeout 120s 120s;

Default:    keepalive_timeout 75s;

Context:    http, server, location

另外,设置较长的keepalive_timeout也可以减少请求SSL会话协商的开销,但同时得考虑并发数,因为keepalive_timeout的值过大,会导致存在很多无效的连接。

keepalive_timeout第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接。

keepalive_timeout第二个参数:可选、在响应的header域中设置一个值“Keep-Alive: timeout=time”;通常可以不用设置。

注:keepalive_timeout默认75s,一般情况下也够用,对于一些请求比较大的内部服务器通讯的场景,适当加大为120s或者300s。

 

keepalive_requests 10000;

Default:    keepalive_requests 100;

Context:    http, server, location

keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭,默认是100。

大多情况下,当QPS(每秒请求数)不是很高时,默认值100凑合够用。但对一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,100就显得太低。QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。

 

keepalive 300;

保持和后端server的长连接。默认情况下Nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx新开一个端口和后端建立连接,请求结束连接回收。为了让nginx和后端server(nginx称为upstream)之间保持长连接,典型设置如下:

http {
    upstream service {
        server   127.0.0.1:8080  weight=1 max_fails=2 fail_timeout=30s;
        server   127.0.0.2:8080  weight=1 max_fails=2 fail_timeout=30s;
        keepalive 300; 
    }
server {
        listen 80;
        server_name service.dancen.com;
        location /  {
            proxy_pass http://service;
            proxy_set_header Host  $Host;
            proxy_set_header x-forwarded-for $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            add_header Cache-Control no-store;
            add_header Pragma  no-cache;
            proxy_http_version 1.1; 
            proxy_set_header Connection "";
        }
    }
}

设置了长连接,Nginx会接受客户端的请求,处理完成之后Nginx会继续保持和后端的长连接,如果并发请求超过了keepalive指定的最大连接数,Nginx会启动新的连接 来转发请求,新连接在请求完毕后关闭,而且新建立的连接是长连接。keepalive 指定的数值是Nginx每个worker连接后端的最大长连接数,而不是整个Nginx的。而且这里的后端指的是所有的后端,而不是每一个后端。

 

proxy_http_version 1.1;

proxy_set_header Connection "";

HTTP协议中对长连接的支持是从1.1版本之后才有的,因此要使用长连接,就得通过proxy_http_version指令设置为”1.1”。

清理从client过来的http header,因为即使是client和nginx之间是短连接,nginx和upstream之间也是可以开启长连接的。这种情况下必须清理来自client请求中的”Connection” header。

 

TIME_WAIT问题:

Nginx和后端的长连接不够用时Nginx会新建连接来处理新的请求,而我们的配置已经配置了使用HTTP1.1,建立连接后,后端认为是长连接而不会主动关闭连接(一般有个空闲超时),关闭连接由Nginx来做了,所以Nginx会出现大量的TIME_WAIT。

而默认情况下,Nginx用HTTP1.0请求后端,后端处理完成后就主动关闭连接,所以 TIME_WAIT出现在后端。

那么现在有新的问题了,如果开启了长连接,而长连接又大量不够用,此时Nginx存在的 TIME_WAIT可能会大量占用端口,导致端口用尽,如果用尽,后果很严重,因此keepalive要慎重设置。

另外,keepalive_requests设置比较小,高并发下超过此值后Nginx会强制关闭和客户端保持的keepalive长连接,也会导致nginx出现TIME_WAIT。

 

补充内容

client_max_body_size 20m;

Context:    http, server, location

在nginx使用过程中,如果需要上传文件,通常需要设置nginx报文大小限制(默认1m),避免出现413 Request Entity Too Large。

 

TLS1.2

问题:

当在Nginx上设置某个站点的ssl_protocols为TLS1.2时,发现访问站点依然使用的是TLS1.0。

解决办法:

当Nginx上配置了多个站点时,只将某个站点修改成TLS1.2无效,需要将所有的站点统一修改为TLS1.2。

你可能感兴趣的:(WEB,网络应用)