Canary Workshop

Whatever is worth doing at all is worth doing well

nginx下可实用的ChaCha20算法、双证书、Brotli压缩的部署

最近完成了OpenSSL 1.1.0的安装,但在使用过程中发现了一些问题,花了一晚上解决它们并记录在此。问题如下:
1、无法在学校机房的XP系统上访问
2、无法在安卓设备上使用ChaCha20算法
这些OpenSSL的问题迫使我重新编译安装nginx,于是这次顺带升级nginx为1.11.4,编译了Brotli模块,并启用了EC 384+RSA 4096双证书,全过程记录如下。

一、实现XP系统正常访问

天朝上国,无奇不有。各类学校机房仍在使用XP系统,而我又有在学校访问的需求,因此爬文得出结论,若想在XP系统访问,需要:
1、使用RSA证书
2、使用TLS_RSA_WITH_3DES_EDE_CBC_SHATLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA为加密套件,这两个家伙是XP支持的仅有的两个比较安全的套件(IE8+有效,相信IE6也很少见了)

双证书下面会提到,在OpenSSL 1.1.0中却得到如下结果:

1
2
3
root@dyn:~# openssl ciphers -v '3DES'
Error in cipher list
139924959090328:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1380:

后来确认OpenSSL 1.1.0默认不编译3DES算法,如果一定要使用则可在nginx编译参数内加入--with-openssl-opt=-enable-weak-ssl-ciphers,但为了保证ChaCha20正常工作我选择了降级OpenSSL到1.0.2h(见下)。之后3DES算法成功打开。

二、配置可实用的ChaCha20

尽管OpenSSL 1.1.0支持了ChaCha20算法,但其支持的是RFC版本(0xcca8、0xcca9),而我使用该算法的场景为安卓设备,安卓设备只支持Draft草案版本(0xcc13、0xcc14),因此OpenSSL 1.1.0无法满足需要RFC版本只有PC的Chrome和Firefox能使用,但PC上用AES128岂不美哉,因此最终决定降级,并打上CloudFlare的补丁(给OpenSSL 1.0.2h同时加入RFC版本和Draft版本的支持,事实上只使用后者)

1
2
3
4
5
6
7
8
9
10
wget -O openssl.zip -c https://github.com/openssl/openssl/archive/OpenSSL_1_0_2h.zip
unzip openssl.zip
mv openssl-OpenSSL_1_0_2h
git clone https://github.com/cloudflare/sslconfig
cd openssl-OpenSSL_1_0_2h
patch -p1 < ../sslconfig/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102g.patch
cd ../

nginx的编译参数指向该打过补丁的OpenSSL 1.0.2h源码目录即可,安装后可正常使用Draft版本的ChaCha20,同时非安卓设备还可自动适配其他更优算法。

三、Brotli模块的编译使用

Brotli是Google大法开发的新式信仰压缩算法,详情参考Wiki页面。安装步骤如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
apt install autoconf libtool automake
git clone https://github.com/bagder/libbrotli
cd libbrotli
./autogen.sh
./configure
make
sudo make install
#x86系统:#
ln -s /usr/local/lib/libbrotlienc.so.1 /lib
#x64系统:#
ln -s /usr/local/lib/libbrotlienc.so.1 /lib64
cd ..
git clone https://github.com/google/ngx_brotli.git

然后在nginx的编译参数内加入诸如--add-module=../ngx_brotli的参数。安装完成后打开nginx.conf文件,加入如下字段:

1
2
3
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;

如果是某些Node.js的后端(Ghost不需要)可能还需发送一个代理Header告知后端不使用GZip算法

1
proxy_set_header Accept-Encoding "";

重启nginx后可以到这里来测试是否成功。

四、双证书的部署

若要实现支持XP系统,光使用3DES算法还不够,还必须使用RSA算法的SSL证书。所幸nginx已支持双证书并可智能判断发送哪一个,只需在虚拟主机内类似这样设置即可:

1
2
3
4
ssl_certificate /usr/local/nginx/ssl/ecc.crt;
ssl_certificate /usr/local/nginx/ssl/rsa.crt;
ssl_certificate_key /usr/local/nginx/ssl/ecc.key;
ssl_certificate_key /usr/local/nginx/ssl/rsa.key;

同时安利下我在使用的加密套件组合,可根据需要更改:

1
ssl_ciphers EECDH+CHACHA20-draft:EECDH+CHACHA20:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;

附:SSL Labs的测试结果:
alt
不要吐槽我为何没开HSTS和HPKP= =