V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaolvmu
V2EX  ›  分享发现

Nginx 配合 BoringSSL 进行编译,并且启用 chacha20-poly1305 加密教程

  •  
  •   xiaolvmu · 2015-03-05 11:13:21 +08:00 via Android · 10768 次点击
    这是一个创建于 3549 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这是一篇很特殊的教程。对于大多数网站来说,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/openssl
    2:我们的选择主要是 LibreSSL(OpenBSD 创建的 OpenSSL 分支) 和 BoringSSL(Google 创建的 OpenSSL 分支)。
    你可以参考的资料:
    https://boringssl.googlesource.com/boringssl/
    http://m.slashdot.org/story/203641
    http://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=20150304092744
    2.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.gz

    BoringSSL 源码
    git clone https://boringssl.googlesource.com/boringssl
    2:假定的目录
    /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/CMake

    cd /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_purge
    Google 的 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.gz
    tar -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

    六:我想说的

    安全性是一个永恒的话题。
    安全性会牺牲很多东西,例如兼容性,例如加载网页的速度。
    不要太过于追求安全性,而我们,需要在安全性和易用性之间,做出一个较好的权衡。

    11 条回复    2015-05-14 18:03:55 +08:00
    xiaolvmu
        1
    xiaolvmu  
    OP
       2015-03-05 11:14:27 +08:00 via Android
    V2EX 太酷炫了,引用 Github 链接竟然直接出来 Showcase(>﹏<)
    0x1e240
        2
    0x1e240  
       2015-03-05 14:48:32 +08:00 via Android
    简直炫酷,继续Apache
    😯
    xiaolvmu
        3
    xiaolvmu  
    OP
       2015-03-05 17:48:55 +08:00 via Android
    额……
    其实 Apache 有的,Nginx 大多都有,实在找不出来用 Apache 的理由……
    mafuyu
        4
    mafuyu  
       2015-03-05 23:00:24 +08:00
    简直是炫酷,默默地继续用LibreSSL来实现CP...
    (副音轨:CP根本就只能拿来卖萌用么 (╯°Д°)╯︵ ┻━┻)
    xiaolvmu
        5
    xiaolvmu  
    OP
       2015-03-06 00:21:35 +08:00 via Android
    哈哈~每天坚持卖萌(>﹏<)
    lhbc
        6
    lhbc  
       2015-03-06 02:49:28 +08:00   ❤️ 1
    futursolo
        7
    futursolo  
       2015-03-07 11:11:07 +08:00   ❤️ 1
    Nginx支持动态库,用--with-openssl=shared就OK,只不过那样就没办法使用自定义的SSL库了。
    LibreSSL2.1.2及2.1.3需要给Nginx打Patch才可用。2.1.4就恢复正常了,而且集成了SSL_Fallback_SCSV,测试也可以拿到A+了。
    xiaolvmu
        8
    xiaolvmu  
    OP
       2015-04-03 10:52:23 +08:00
    终于放假了~
    话说,有的 gcc 不支持 sandybridge 这个 march,如果 sed 的时候选择 sandybridge 不起作用,就用
    march=native,需要 gcc 4.2 以上。
    xiaolvmu
        9
    xiaolvmu  
    OP
       2015-04-03 10:53:31 +08:00
    话说 libressl 发布 2.1.6 了,他们刷版本号好疯狂,刚编译完2.1.5。。
    xiaolvmu
        10
    xiaolvmu  
    OP
       2015-04-03 10:58:04 +08:00
    新动态:
    新版本1.7.11的 nginx,编译 boringssl 出错了......
    找了下,在nginx源码的 /src/event/openssl.c 的 1900 行附近有一个 SSL_R_BLOCK_CIPHER_PAD_IS_WRONG ,去掉就可以编译了。可是不知道这有什么影响。
    windydays
        11
    windydays  
       2015-05-14 18:03:55 +08:00
    之前做了一个nginx+openssl+chacha20-poly1305的配置,可以看:
    https://blog.helong.info/blog/2015/05/08/https-config-optimize-in-nginx/
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3293 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:00 · PVG 20:00 · LAX 04:00 · JFK 07:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.