zvv

Nginx 配置上更安全的 SSL & ECC 证书 & Chacha20 & Certificate Transparency

文章修订记录

// Generate RSA key
openssl genrsa -out private.key 4096

// Generate ECC key
openssl ecparam -genkey -name secp384r1 -out private-ecc.key

// Generate CSR
openssl req -new -sha384 -key private-ecc.key -out www_pupboss_com.csr

关于 ECC 证书,好处就不多说了,256 位的证书加密强度比 2048 位的 RSA 都高,还避免了性能消耗 吗?。

谷歌一搜 ECC 证书,首页已经被沃通承包了,他不断夸大自己的数据,说 ECC 如何如何好,对移动设备友好,兼容 XP Android 2.1.x 等等等等,其实生产环境并没发现有什么优势,正常的 ECC 反而不兼容 Android 2.x,XP。

沃通颁发的 ECC 证书是经过特殊处理的(如果他的 ECC 证书真的兼容 XP Android 2.1.x),猜测是采用了传说中的双证书。

实测 ECC 的性能消耗跟加密程度一样强悍,384 位的 ECC 给 CPU 造成的压力和 3000 位左右的 RSA 一样,那要是 4096 位的 ECC,那效果,简直爆炸。

secp384r1 是一个曲线名,openssl ecparam -list_curves 可以看所有的曲线名。

经过测试,

CSR 的 SHA1 加密不影响生成的证书用 SHA256 加密!

CSR 的 SHA1 加密不影响生成的证书用 SHA256 加密!

申请完 SSL 证书,应该有以下几样东西

首先把证书商提供的根证书中级证书添加到自己的证书后面,不然有的浏览器可能报错,我的习惯是域名证书 + 中级证书 + 根证书,别的顺序不知道行不行。

当然这些是最初级的,下面来点高级的东西,先上臭美图两张:

测试地址:SSL Labs

SSL 协议

SSLv2 是不安全的,绝对不能用,SSLv3 能不用则不用,正常情况下用不到的,推荐使用 TLSv1 TLSv1.1 TLSv1.2,附配置代码:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

加密算法

RC4 不要用,再就是 OpenSSL 记得更新到最新版,可以避免很多麻烦。别的也没什么了,附代码:

ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

ssl_prefer_server_ciphers on;

如果你的 OpenSSL 版本比较旧,不可用的加密算法会被自动丢弃。最好使用完整套件,让 OpenSSL 自动选择。所以套件的顺序就灰常重要

强制丢弃的算法

但是 ECC 证书的部署不大一样,加密套件和 RSA 不一样,用错之后会影响向前安全性(Forward secrecy)。

加密套件应该这么改:

ssl_ciphers "EECDH+CHACHA20 EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";

前向安全性(Forward Secrecy)

首先 Nginx 配置上如下代码:

ssl_dhparam /your/path/to/dhparam.pem;

pem 文件是这样生成的:

openssl dhparam -out dhparam.pem 4096

然后会显示

This is going to take a long time
.......+...........................+............................+............................+............++*++*++*

当时这个命令,VPS 上单核执行了 100 分钟,我的电脑 i7 4750HQ 处理器,只能跑一个核,用了大概 70 分钟,VPS 上生成的 ..+... 字符数大概在 50000 个,我的电脑产生了 74900 多个,不知道什么原因

以下内容来自 @justwd 的邮件:

dhparam 算法是在 2^4096 个数字中找出两个质数,所以需要的时间挺长。..... 意思是有可能的质数,+是正在测试的质数,* 是已经找到的质数。

前向安全性(Forward Secrecy)的概念很简单:客户端和服务器协商一个永不重用的密钥,并在会话结束时销毁它。服务器上的 RSA 私钥用于客户端和服务器之间的 Diffie-Hellman 密钥交换签名。从 Diffie-Hellman 握手中获取的预主密钥会用于之后的编码。因为预主密钥是特定于客户端和服务器之间建立的某个连接,并且只用在一个限定的时间内,所以称作短暂模式(Ephemeral)。

如果使用前向安全机制,攻击者取得了一个服务器的私钥,他是不能解码之前的通讯信息的。这个私钥仅用于 Diffie Hellman 握手签名,并不会泄露预主密钥。Diffie Hellman 算法会确保预主密钥绝不会离开客户端和服务器,而且不能被中间人攻击所拦截。

所有版本的 nginx 都依赖于 OpenSSL 给 Diffie-Hellman 的输入参数。如果不特别声明,将使用 OpenSSL 的默认设置,1024 位密钥。这绝壁是不安全的,因为我们正在使用 2048 位证书,所以要有一个更强大的 DH

HTTP 严格传输安全(HSTS)(HTTP Strict Transport Security)

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

接下来的半年,都会保持直接发送 HTTPS。

配置 OCSP 装订

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /you/path/to/domain.chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;(国外)
resolver 223.5.5.5 223.6.6.6 valid=300s;(国内)
resolver_timeout 10s;

domain.chain.pem 里面是域名证书到 ROOT 证书的一个链。

连接到一个服务器时,客户端应该使用证书吊销列表(CRL)或在线证书状态协议(OCSP)记录来校验服务器证书的有效性。CRL 存在一个问题,它已经增长的太快,永远也下载不完。

OCSP 更轻量一些,只需发一个请求。但是副作用是访问一个站点时必须对第三方 OCSP 响应服务器发起 OCSP 请求,这就增加了延迟带来的潜在隐患。事实上,CA 所运营的 OCSP 响应服务器非常不可靠,浏览器如果不能及时收到答复,就会静默失败。攻击者通过 DDoS 攻击一个 OCSP 响应服务器可以禁用其校验功能,这样就降低了安全性。

解决方法是允许服务器在 TLS 握手中发送缓存的 OCSP 记录,以绕开 OCSP 响应服务器。这个机制减少了客户端和 OCSP 响应服务器之间的通讯,称作 OCSP 装订。

客户端会在它的 CLIENT HELLO 中告知其支持 status_request TLS 扩展,服务器仅在客户端请求它的时候才发送缓存的 OCSP 响应。

大多数服务器最长会缓存 OCSP 48 小时。服务器会按照常规的间隔连接到 CA 的 OCSP 响应服务器来获取刷新的 OCSP 记录。OCSP 响应服务器的位置可以从签名的证书中 Authority Information Access 字段中获得。

我的服务器是这么配置的:

server {

    listen 443 ssl http2 default;
    server_name www.pupboss.com;
    client_max_body_size 10M;

    ssl_certificate ssl/pupboss.com_ecc.cer;
    ssl_certificate_key ssl/pupboss.com_ecc.key;

    ssl_dhparam ssl/dhparam.pem;

    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
    ssl_ecdh_curve secp384r1;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 223.5.5.5 119.29.29.29 valid=300s;
    resolver_timeout 10s;

    add_header X-Frame-Options deny;
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    add_header X-Content-Type-Options nosniff;
}

正常情况下,这样配置完之后,测试就会显示 A+ 了。

重启免密码

有的时候生成 key 的时候,手贱输了密码,敲入如下指令可以解除:

openssl rsa -in pupboss.key -out pupboss_unsecure.key

强制 HTTPS

加上如下代码

server {

    listen 80 default;
    server_name www.pupboss.com;

    return 301 https://$server_name$request_uri;
}

配置 Chacha20 和 Certificate Transparency

Chacha20 和 Certificate Transparency 相关的配置网上都有,我再写也写的差不多,看着跟抄袭的一样,我先附上参考链接:

写的都挺好的,我就直接贴一个脚本吧。具体教程上他们博客看去。

下面的脚本适用于 Debian x64 系统,并且使用 apt-get 安装 mainline version 的 Nginx 的机器,其他的可能得根据自己编译的参数,重新改改~编译完的二进制大概是 12M,A 机器上编译的,拷贝到 B 机器,chmod +x 之后,是可以运行的,只要系统版本一样。

注意:Certificate Transparency 相关的需要一台境外服务器的支持,因为谷歌被 Ban 了。

#!/bin/bash

cd /opt/chacha20

NG_VERSION=nginx-1.9.11

wget http://nginx.org/download/$NG_VERSION.tar.gz
tar -zx -f $NG_VERSION.tar.gz
wget -O nginx-ct.zip https://github.com/grahamedgecombe/nginx-ct/archive/master.zip
unzip nginx-ct.zip

wget -c https://github.com/openssl/openssl/archive/OpenSSL_1_0_2-stable.zip
git clone https://github.com/cloudflare/sslconfig
unzip OpenSSL_1_0_2-stable.zip && mv openssl-OpenSSL_1_0_2-stable openssl

cd openssl && patch -p1 < ../sslconfig/patches/openssl__chacha20_poly1305_cf.patch
cd /opt/chacha20/$NG_VERSION/

./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=%{_libdir}/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_v2_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,--as-needed' --with-ipv6 --with-openssl=../openssl --add-module=../nginx-ct-master

make

service nginx stop
mv objs/nginx /usr/sbin/nginx
service nginx start
cd /opt/chacha20
rm -rf *

via.https://www.pupboss.com/nginx-add-ssl/

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »

因本文不是用Markdown格式的编辑器书写的,转换的页面可能不符合AMP标准。