JUN

SSL证书&Nginx 配置最佳实践
最佳配置下面是可以在 ssllabs 拿到 A+,各项均为满分的配置。首先是80端口的配置,假设你用的是 Let'...
扫描右侧二维码阅读全文
20
2019/06

SSL证书&Nginx 配置最佳实践

最佳配置

下面是可以在 ssllabs 拿到 A+,各项均为满分的配置。

ssllabs.png

首先是80端口的配置,假设你用的是 Let's Encrypt,需要设置.well-known文件夹的访问路径。其它访问全部重定向到https。

server {
    listen 80;
    listen [::]:80;

    server_name your domain;

    location ^~ /.well-known/ {
        root /home/wwwroot/domain.com;
    }

    location / {
        return 301 https://$host$request_uri;
    }

}

注:这些配置不会影响到 ssllabs 的得分。

接下来是443端口的配置:

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name  your domain;
        #access_log  your access_log path main;
        error_log your web path/logs/error.log warn;

        ssl_certificate your cert path
        ssl_certificate_key your cert path/

        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384";
        ssl_ecdh_curve secp384r1;
        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout  60m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate your cert path/letsencrypt-full-chain.pem;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;
        #add_header Strict-Transport-Security "max-age=63072000;";
        #add_header X-Frame-Options DENY;
        #add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header Expect-CT "max-age=0";

        ##################################
        # END https://cipherli.st/ BLOCK #
        ##################################
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

        location ~ /.well-known {
                allow all;
        }

        # The rest of your server block
        root   website path;
        index index.html index.php index.htm;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
            try_files $uri $uri/ =404;
        }
    

        ## Your only path reference.
        ## This should be in your http block and if it is, it's not needed here.
        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }


}

满分配置详解

这一节主要说明一下如何在 ssllabs 各个部分拿到满分。

Certificate 部分

这一部分很容易拿到满分。只要保证你的证书链顺序是正确的,并且没有使用 SHA1(应该使用SHA256)作为证书签名算法。
还有就是你的CA一定要是业界知名的。

Protocol Support 部分

如果你使用 TLSv1.2 及以上配置,这部分会得到满分。
ssl_protocols TLSv1.2 TLSv1.3;
如果是 TLSv1.1&1.2,这部分会得95分。
ssl_protocols TLSv1.1 TLSv1.2;
如果是 TLSv1.0~1.2,这部分只会得90分。
ssl_protocols TLSv1.0 TLSv1.1 TLSv1.2;
需要注意的是,你不应该再使用1.0版,因为它已经被弃用了。

Key Exchange 部分

如果你使用 RSA4096 或者 secp256 以上的 ECC 证书,那么这部分就会得到满分。
如果你需要 ECC 证书可以试试 acme.sh 客户端。certbot 也可以,但是比较麻烦。
下面以 certbot 为例生成 ECC 证书。
首先需要生成一个 ECC key

openssl ecparam -genkey -name secp384r1 -noout -out privkey.pem

然后根据这个 key 来生成 CSR

openssl req -new -sha256 -key privkey.pem -out ecc.csr

注意要在 Common Name 那里写上你的域名。
最后再用 certbot 命令生成证书即可。

certbot certonly --csr ecc.csr --webroot -w /home/wwwroot/domain.com -d domain.com

一般来说 certbot 会在 /etc/letsencrypt/live 下面根据域名为你生成证书目录,但是以 CSR 方式签发的不会。
它会在当前目录下生成三个文件:
0000_cert.pem --- 服务器证书(也就是 cert.pem)
0000_chain.pem --- 中间证书(也就是 chain.pem)
0001_chain.pem --- 证书链(也就是 fullchain.pem)
重命名一下以便更好理解:

mv 0000_cert.pem cert.pem
mv 0000_chain.pem chain.pem
mv 0001_chain.pem fullchain.pem

另外,你还需要生成一个DH密钥交换证书。
命令为openssl dhparam -out dhparam.pem 4096

需要注意的是,如果你同时有 RSA/ECC 和 DH 密钥交换证书,ssllabs 会以加密强度最小的那个为基准。
比如你有 4096RSA 证书,但是 DH 的证书是 2048 的,你会得到90分。

Cipher Strength 部分

加密套件只要大于256bit就可以拿到满分。

ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384';

但是一般来说,为了更好的兼容性,还是128强度的比较好。(80分)

ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';

左侧字母拿到 A+

只要启用HSTS就可以拿到A+。
HSTS是表示这个网站只能通过HTTPS访问的技术。

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;preload" always;

可选配置

ssl_ecdh_curve secp384r1; (如果不用 ECC 证书可以不用设置)

补充说明

1.安全套件(ssl_ciphers)配置可以参考mozilla给出的几种配置:
https://wiki.mozilla.org/Security/Server_Side_TLS
这个网站列出了最优配置、最普遍的配置以及兼容性最好的配置。

2.如果你开启了TLSv1.3,因为TLSv1.3默认开启了TLS_AES_128_GCM_SHA256,会被 ssllabs 判定为不够强的加密套件(Cipher Strenth只能拿90分)。现在这个issue好像正在修改中。详情请看:
https://github.com/ssllabs/ssllabs-scan/issues/636#issuecomment-461727819

你可以暂先用TLSv1.2。
当然你也可以手动设置TLSv1.3的默认加密套件。方法如下:
修改openssl.conf文件,一般在/etc/ssl/openssl.cnf下。在ciphersuites里列出默认使用的加密套件。

openssl_conf = default_conf

[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
ciphersuites = TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384

这里说一句题外话,CHACHA好像比AES要快(未验证),所以我们把CHACHA放前面。
但是如果你这么改了,在 ssllabs 里会收到警告:

This server does not support the mandatory cipher suite TLS_AES_128_GCM_SHA256 for TLS 1.3. See RFC 8446 for details.

这是因为在TLSv1.3标准里这个套件是必须的。
有兴趣的话可以看看IETF的文档。
https://tools.ietf.org/html/rfc8446#section-9.1

参考网站

https://www.404forest.com/2017/05/08/get-aplus-score-in-ssllabs-with-nginx-and-letsencrypt/
https://community.letsencrypt.org/t/howto-a-with-all-100-s-on-ssl-labs-test-using-nginx-mainline-stable/55033
https://qiita.com/ooxif/items/431c5d6db68cc46db60d

Last modification:July 2nd, 2019 at 09:25 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment