这是一篇很特殊的教程。对于大多数网站来说,OpenSSL 足够稳定和兼容。因此 ChaCha20-Poly1305 系(以下简称CP)加密似乎是不必要的。
但是,ChaCha20-Poly1305 加密在 ARM 平台上有着先天的优势。
根据测试,在许多移动设备上,ChaCha20-Poly1305 加密的速度是 AES 的3倍还多。这样,网站在移动设备上的体验将会更好。虽然这种优化很难感受到,远没有 fcgi_cache/pagespeed 之类明显,不过为了信仰,还是要试一试。
一:方案的选择。
1:至今 OpenSSL 还没能在生产环境中支持 ChaCha20-Poly1305 加密。
在一个特殊的分支中,OpenSSL 添加了对这种加密的支持,叫做 the 1.0.2-aead branch。不过依然不建议使用。
你可以参考的资料:
https://www.onwebsecurity.com/cryptography/openssl2:我们的选择主要是 LibreSSL(OpenBSD 创建的 OpenSSL 分支) 和 BoringSSL(Google 创建的 OpenSSL 分支)。
你可以参考的资料:
https://boringssl.googlesource.com/boringssl/http://m.slashdot.org/story/203641http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/3:关于 Web 服务器。
在 Apache HTTP Server 下,BoringSSL 和 LibreSSL 会导致 mod_ssl 出错,只有用 nginx 对其进行反代才有可能实现。而反代对资源消耗太大,因此,我们在方案中直接弃用 Apache,使用 Nginx。注意,以下所有的资料都针对 Nginx HTTPS Webserver。
4:LibreSSL or BoringSSL?
就在前天,LibreSSL 的 2.1.4 版本发布了。
实现这套加密时,我最开始选择的加密库是 LibreSSL,因为资料非常齐全。但是我仅仅编译成功了 LibreSSL 2.1.1 版本,在高于 2.1.1 的版本中,存在一个特殊的编译问题,经过我的测试,2.1.2/2.1.3 版本都不能和 Nginx 1.7.10 一起编译成功。因为 2.1.4 刚刚出来,我还没有测试,大家可以试一试。
LibreSSL 的 2.1.4 更新日志:
http://undeadly.org/cgi?action=article&sid=201503040927442.1.2 编译问题的相关讨论:
https://github.com/libressl-portable/portable/issues/51最终,我选择 BoringSSL 作为解决方案。
5:为什么不采用 LibreSSL?
在 LibreSSL 2.1.2 所有以前的版本中均存在一个可导致拒绝服务攻击的漏洞。
在
ssllabs.com 中,使用 LibreSSL 2.1.2 以下版本时,会有一个特殊的警告。
This server doesn't support TLS_Fallback_SCSV.
这方面的讨论非常多,你可以参考的资料:
https://tools.ietf.org/html/draft-bmoeller-tls-downgrade-scsv-01(虽然这一篇我看不懂。。。)
而 LibreSSL 2.1.2 和 2.1.3 版本会导致无法 make nginx,而且没有方便的解决方案/patch。
因此我们不再考虑 LibreSSL。
二:BoringSSL 的编译
花了这么多篇幅讲述方案的选择,再写编译就很明了了:
1:使用的软件包
稍后用到
Nginx Mainline 1.7.10:
http://nginx.org/en/download.html或者 wget
http://nginx.org/download/nginx-1.7.10.tar.gzBoringSSL 源码
git clone
https://boringssl.googlesource.com/boringssl2:假定的目录
/boring
--boringssl
--nginx-1.7.10.tar.gz
3:处理链接搜索路径:
cd /boring/boringssl
sed -i \
-e 's:-ggdb -std=c89:-std=c89 -march=sandybridge -O2 -pipe -fdiagnostics-color=always:' \
-e 's:-ggdb -std=c++0x:-std=c++0x -march=sandybridge -O2 -pipe -fdiagnostics-color=always:' \
-e '/^add_subdirectory(ssl\/test)/d' \
-e '/^add_subdirectory(tool)/d' \
CMakeLists.txt
这些命令来自 Github @
wmark install.sh。在我执行的时候,只sed了后3行,似乎没有问题,不过建议大家全部执行。
使用这个 install.sh 也是不错的办法,不过centos 7 x64失败了,只有手动来了。
4:开始编译 BoringSSL
先安装 CMake,在这里找 releases
https://github.com/Kitware/CMakecd /boring/boringssl
mkdir build &&cd build
cmake ../ && make
cd ..
5:处理加密库,使它兼容 OpenSSL
cd /boring/boringssl
mkdir -p .openssl/lib
ln -s include /boring/boringssl/.openssl/
#
注意!在这一步中,链接到的目录最好是绝对路径,不然容易在进入时出现
Too many levels of symbolic links
#
cp build/crypto/libcrypto.a build/ssl/libssl.a .openssl/lib
#注意,如果你在编译时没有输出 libssl.a/libcrypto.a,说明编译错误了
#
三:Nginx 的编译
Nginx 不支持动态so库,所有的模块必须编译时一起编译进去。
1:分享一下我的 nginx config参数:
[root@default ~]# /etc/sbin/nginx -V
TLS SNI support enabled
configure arguments: --prefix=/etc --user=nginx --group=nginx --with-openssl=../boringssl --with-ld-opt=-lrt --with-http_spdy_module --with-http_ssl_module --with-http_stub_status_module --with-pcre --add-module=../ngx_cache_purge-2.3 --add-module=/boring/ngx_pagespeed-1.9.32.3-beta
我额外使用了 cache purge 和 pagespeed 模块。
Frickle 的 ngx_cache_purge 模块:
https://github.com/FRiCKLE/ngx_cache_purgeGoogle 的 ngx_pagespeed 模块:
https://github.com/pagespeed/ngx_pagespeed找到 release,解压即可,add-module 的路径必须是绝对路径。
注意:ngx_pagespeed 需要 psol
cd /path/to/pagespeed/module
wget
https://dl.google.com/dl/page-speed/psol/1.9.32.3.tar.gztar -xzvf 1.9.32.3.tar.gz # expands to psol/
发现扯远了-_-||继续说 boringSSL
--with-openssl=../boringssl --with-ld-opt=-lrt --with-http_ssl_module
这是必要的编译参数。
2:开始编译
注意!这时需要先更新 ssl.h 的文件时间,防止被 nginx 重新编译导致 make nginx 失败。
cd /boring/boringssl/.openssl/include/openssl
touch ssl.h
cd /boring/nginx-1.7.10
make
3:安装 nginx
make upgrade
四:Nginx 的配置
server {} 字段
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;ssl_ciphers CHACHA20:AES128:AES256:GCM:!DH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;add_header Strict-Transport-Security max-age=31536000;ssl_prefer_server_ciphers on;
PS:BoringSSL 默认禁用 SSLv3。
五:其他的 nginx 安全配置
1:HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
可以多配置几个:
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
2:SPDY 3.1 的实现
listen 443 ssl default spdy
add_header Alternate-Protocol 443:npn-spdy/3.1;
3:完美向前保密(PFS)
openssl dhparam -rand - 2048 >> /path/to/my-key.crt
#这需要比较长的时间。
2048 位还是不错的选择,我在生成的时候选择了 4096 位,后悔了。。
#
4:对于使用 StartSSL 证书的同学
http://www.startssl.com/certs/class1/sha2/pem/也有 sha2 加密的哦(>﹏<)
#configuration
ssl_dhparam /etc/conf/dh4096.pem
六:我想说的
安全性是一个永恒的话题。
安全性会牺牲很多东西,例如兼容性,例如加载网页的速度。
不要太过于追求安全性,而我们,需要在安全性和易用性之间,做出一个较好的权衡。
完