增強Nginx的SSL安全性和性能

你的站點啓用https了嗎?如果啓用了,其安全性如何呢?

到站長工具:

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

 

輸入網址檢測一下,就可以看到報告:

以上這個結果說明基本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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章