分类目录归档:HTTPS

openssl 探测证书过期时间

true | openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux

这边一直都是用这个来探测证书的健康的, 在内网的使用还可以, 在公网探测中就很容易出现僵死的情况

后来在sererfault.com查到可以用timeout + 命令来解决

https://serverfault.com/questions/361464/is-it-possible-to-set-a-timeout-on-openssls-s-client-command

测试时发现”timeout 5 true | openssl …” 的管道会失败, 在公网的探测就傻兮兮的只能用了

timeout 5 openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux

缺点是每条指令都要等5秒, 当然, 结合多进程问题也不是太大…

直到今天, 才发现自己摆了个乌龙, 可以使用timeout 5 bash -c “true | openssl s_client… “, true可以处理实时正常结果, timeout可以处理异常结果

timeout 5 bash -c "true | openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux "

客户端证书认证

双向认证, 就是客户端和服务端均需要证书认证身份的一种双向认证形式

这里主要介绍下客户端证书的配置

openssl genrsa -out root.key 1024

openssl req -new -out root.csr -key root.key

openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650

openssl genrsa -out client.key 1024

openssl req -new -out client.csr -key client.key

openssl x509 -req -in client.csr -out client.crt -signkey client.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650

nginx配置

ssl_client_certificate ssl/client.crt;
ssl_verify_client on;

这个是给客户端导入的p12格式证书

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

静态编译curl 和 可选静态编译依赖库

新版的curl 支持了更细致时间粒度的curl_easy_getinfo,以及HTTP2, 这里介绍手工编译源码安装方式,并使用openssl1.1.1b

  1. https://www.openssl.org/ 下载1.1.1 序列的long-term 源码,并编译安装 ./config --prefix=/opt/itc/openssl enable-weak-ssl-ciphers no-shared && make && make install
  2. https://nghttp2.org/ 下载nghttp2库, curl 需要它才能支持HTTP2,编译安装, OPENSSL_LIBS="/opt/itc/openssl/lib/" ./configure --prefix=/opt/itc/curl/nghttp2 –enable-static=yes –enable-shared=no && make && make install
  3. 从https://curl.haxx.se/ 下载最新的curl版本,并编译安装,编译参数如下
./configure  LDFLAGS="-static" --prefix=/opt/itc/curl --with-ssl=/opt/itc/openssl  --with-nghttp2=/opt/itc/curl/nghttp2 --disable-ldaps --without-libidn2 --enable-static=yes --enable-shared=no
make
make install

这样子得到的是不依赖openssl和nghttp2动态链接库的curl,可以拷走给别的机器

./configure  LDFLAGS="-static" --prefix=/opt/itc/curl --with-ssl=/opt/itc/openssl  --with-nghttp2=/opt/itc/curl/nghttp2 --disable-ldaps --without-libidn2 --enable-static=yes --enable-shared=no
make LDFLAGS="-all-static -static -L/opt/itc/openssl/lib -L/opt/itc/curl/nghttp2/lib -ldl"
make install

这样子得到的是: 不依赖任何动态链接库的版本

可能遇到的问题:

1./usr/bin/ld: cannot find -lnghttp2 或者 -lssl 之类的

这是curl找不到对应的依赖库,请确认给了正确的configure参数,如果还不行,可以在configure的时候加上LIBS=-L/opt/itc/openssl/lib/ -L… 多个依赖库以空格分开

2. configure: error: one or more libs available at link-time are not available run-time. Libs used at link-time: -lnghttp2 -lssl -lz -lrt -lcrypto -ldl

这是curl找到了link-time 库,却没找到动态依赖库, 需要在configure的时候加入LDFLAGS=”-static”,让curl的编译程序知道我们要做静态的东西

3. 静态编译make的时候为什么要带那么长的参数,通常不是LDFLAGS=”-all-static”就可以了么?

是的,通常是可以的,打开src/Makefile能看到make LDFLAGS 带的参数会冲掉configure的时候找到的依赖库环境

LD = /usr/bin/ld -m elf_x86_64
 LDFLAGS = -static -L/opt/itc/openssl/lib -L/opt/itc/curl/nghttp2/lib
 LIBCURL_LIBS = -lnghttp2 -lssl -lrt -lcrypto -ldl

所以要么完整一点写上去,要么就使用curl提供的curl_LDFLAGS参数也OK

make curl_LDFLAGS="-all-static"

4. 那么要用这些新的库编译example里边的例子怎么办?

 #gcc  chkspeed.c /opt/itc/curl/lib/libcurl.a /opt/itc/curl/nghttp2/lib/libnghttp2.a /opt/itc/openssl/lib/libssl.a /opt/itc/openssl/lib/libcrypto.a  -I/opt/itc/curl/include -I/opt/itc/curl/nghttp2/include   -lrt  -ldl  -o chkspeed
 #ldd chkspeed
        linux-vdso.so.1 =>  (0x00007ffc475a2000)
        librt.so.1 => /lib64/librt.so.1 (0x00007fcb5d748000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fcb5d544000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fcb5d1af000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fcb5cf92000)
        /lib64/ld-linux-x86-64.so.2 (0x00005593e1eb2000)
这样子编译出来是把这几个库都包含在里边的
gcc chkspeed.c -L/opt/itc/openssl/lib/   -L/opt/itc/curl/nghttp2/lib -L/opt/itc/curl/lib  -I/opt/itc/curl/include -I/opt/itc/curl/nghttp2/include -lcurl -lssl -lrt -lcrypto -ldl -lnghttp2
这样子编译出来是带动态链接库的,但是需要设置环境变量,告诉系统那些.so在哪里,或者修改/etc/ld.so.conf.d/, 增加路径

当然,我们的openssl选择的是静态编译,所以出来的程序依赖只有nghttp2.so

部分知识点:

o: 编译的目标文件
a: 静态库,其实就是把若干o文件打了个包
so: 动态链接库(共享库)

lo: 使用libtool编译出的目标文件,其实就是在o文件中添加了一些信息
la: 使用libtool编译出的库文件,其实是个文本文件,记录同名动态库和静态库的相关信息

./configure LDFLAGS="-static"
make LDFLAGS="-all-static"
-I include,头文件和库文件,通常都是源码
-L 依赖链接库的目录,可能是静态的也可能是动态的
-l 依赖库的名称,比如-lssl -ldl -lz 
pkgconfig 里边有对应的.pc文件,当-l 或者-L指定依赖的时候会自动去找

-l 是有顺序的,而且是从右到左开始包含的,比如

 -lcurl -lssl -lrt -lcrypto -ldl -lnghttp2
这里-lcurl 必须在最前边, -lssl 也必须在-lcrypto的前边,原因很简单: curl调用了所有的其他依赖库, 而ssl调用了crypto

参考文档:

https://github.com/curl/curl/issues/503

https://curl.haxx.se/mail/lib-2017-11/0107.html

https://stackoverflow.com/questions/48726825/setting-up-libcurl-on-linux

https 证书比较 geotrust globalsign verisign digicert

目前收费的证书有几个品牌: 来自于digicert旗下的 Geotrust 和 Digicert, 来自日本的globalsign

digicert: 其实是之前的verisign的替换,由于chrome拒绝掉了symantec的安全认证导致这个品牌的彻底消亡被digicert收购并重新签发证书

优点: 兼容性好,大品牌, RSA ECC双认证, 支持Windows XP SP3 +, iOS5 +, Firefox 2+, Android 1.5+

缺点: 贵, 如果要实现WinXP全兼容,需要Baltimore cross 认证

使用公司: weixin.qq.com www.sohu.com www.zhihu.com等

GeoTurs: 低端品牌, 由于被digicert收购后用新根签发,兼容性大增

优点:  便宜 兼容性好

缺点: 只支持RSA认证, 品牌认知度偏低

Globalsign: 来自日本的证书品牌, 2016年曾出现过中间证书异常吊销的事故,目前占据了越来越多的市场,目前百度 阿里 腾讯 京东 爱奇艺 搜狗都使用这个品牌

优点: 相对便宜,只有之前verisign的一半价格, 兼容性好

缺点:  2016年的事故让人有疑虑,签发过程会比digicert略微繁琐些

整体看: 目前几家商业证书的兼容性基本都在同一水平上, 只剩下品牌认知度的影响

globalsign其实是个非常合适的性价比之选

当然,对于非常计较成本的用户,当然是用免费证书

https://knowledge.digicert.com/generalinformation/digicert-root-compatibility.html

nginx 与 TLS1.3

TLS1.3支持了更优秀的SSL 新特性,可以有效降低https的协商时间,建议升级

本文使用了最新的nginx 1.14.1 (该版本修正了 1.14 H2 cpu/mem 攻击漏洞: low)

#wget https://www.openssl.org/source/openssl-1.1.1.tar.gz
#wget http://nginx.org/download/nginx-1.14.1.tar.gz

#spdy兼容补丁
#wget https://raw.githubusercontent.com/favortel/nginx_patch/master/nginx-1.14.0_spdy_h2.patch

#OKHTTP H2 头部动态压缩兼容补丁
#wget https://raw.githubusercontent.com/favortel/nginx_patch/master/fssnginx_1.14.0_dynamic_table_size.patch

#PCRE ZLIB等
#wget https://ftp.pcre.org/pub/pcre/pcre-8.42.tar.gz
#wget https://zlib.net/zlib-1.2.11.tar.gz

#tar -zxvf openssl-1.1.1.tar.gz
#tar -zxvf pcre-8.42.tar.gz
#tar -zxvf zlib-1.2.11.tar.gz
#tar -zxvf nginx-1.14.1.tar.gz

#cd nginx-1.14.1
#patch -p1 < ../fssnginx_1.14.0_dynamic_table_size.patch
#patch -p1 < ../nginx-1.14.0_spdy_h2.patch

./configure --prefix=/opt/itc/nginx --with-http_stub_status_module --with-http_realip_module --with-http_ssl_module --with-openssl=../openssl-1.1.1 --with-pcre=../pcre-8.42 --with-pcre-jit --with-zlib=../zlib-1.2.11 --with-http_v2_module --with-http_spdy_module
#make && make install

配置比较简单,就是ssl_protocols 增加TLSv1.3就好, ssl_ciphers 不用特意改动:

...
ssl_protocols               TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers                 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers   on;
ssl_ecdh_curve              secp384r1;
...

比如本站,如果您是用chrome访问的是https协议,打开开发者工具-security,就能看到本站使用了TLS1.3了

nginx spdy patch for 1.14.0 1.13.12

spdy 协议由于安卓碎片化的存在 暂时还是需要保留一段时间的兼容性

准备升级到nginx1.14的时候发现 work process 会自动 退出, 同时系统日志有 nginx segfault的信息

修改配置,抓取coredump信息,需要做以下内容
nginx 增加

worker_rlimit_core 5000M;
working_directory /path/to/cores/;
$> ulimit -c unlimited
$> mkdir /opt/coredump/ && chown nobody.nobody /opt/coredump/ # 先建目录,还要确认nginx用户可以写此目录
$> echo “/opt/coredump/core-%e-%p-%h-%t” > /proc/sys/kernel/core_pattern

拿到coredump文件后使用gdb分析

gdb /path/to/nginx /path/to/cores/nginx.core
backtrace full

发现问题指向了
src/http/ngx_http_spdy.c:ngx_http_spdy_state_read_data 的
buf->last = ngx_cpymem(buf->last, pos, size);

简单调试发现buf->last是个0, ngx_cpymem会因为内存越界导致coredump

而分析代码 + gdb 断点调试 看到初始化r->request_body->buf的部分: ngx_http_spdy_init_request_body(r) 并未执行

打印r->request_body 内容发现这块被初始化了,对比nginx1.12.2和1.10.3版本发现旧版本则是未做初始化

翻了下调用的部分:ngx_http_request_body: ngx_http_read_client_request_body 可以看到在nginx 1.13.12版本开始会对r->request_body 做了初始化操作,这部分直接导致了SPDY 补丁 的不兼容

所以答案就很简单了,修改下判断条件即可

新补丁放在了:https://github.com/favortel/nginx_patch/blob/master/nginx-1.14.0_spdy_h2.patch
参考文档:
https://toontong.github.io/blog/nginx-gdb-coredump-segfault.html
https://www.nginx.com/resources/wiki/start/topics/tutorials/debugging/
http://lxr.nginx.org/source/src/http/ngx_http_request_body.c
http://lxr.nginx.org/source/src/http/ngx_http_request_body.c?v=nginx-1.12.2

ciphers suite的选择

HTTPS ciphers suite 的选择要奉行一个原则: 安全 兼容 性能

可以参考https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations 这个链接

Configuration Oldest compatible client
Modern Firefox 27, Chrome 30, IE 11 on Windows 7, Edge, Opera 17, Safari 9, Android 5.0, Java 8
Intermediate Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1, Windows XP IE8, Android 2.3, Java 7
Old Windows XP IE6, Java 6

如果是个人网站,不需要考虑支持较老和古老的浏览器,直接选择Modern支持即可

对于大多数的网站来说,还是需要综合考量的,先假设只需要支持modern和Intermediate

Intermediate compatibility (default)

For services that don’t need compatibility with legacy clients (mostly WinXP), but still need to support a wide range of clients, this configuration is recommended. It is is compatible with Firefox 1, Chrome 1, IE 7, Opera 5 and Safari 1.

  • Ciphersuites: 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
  • Versions: TLSv1.2, TLSv1.1, TLSv1
  • TLS curves: prime256v1, secp384r1, secp521r1
  • Certificate type: RSA
  • Certificate curve: ‘None
  • Certificate signature: sha256WithRSAEncryption
  • RSA key size: 2048
  • DH Parameter size: 2048
  • ECDH Parameter size: 256
  • HSTS: max-age=15768000
  • Certificate switching: None

几个关键点:

  1.  RSA key 用2048的签名就可以了
  2.  DH 用2048
  3.  使用TLS1.0-1.2, 不要使用不安全的SSLv2-3
  4.  加密的cipher-suite 可以参考以上,也可以自己调整顺序,比如可以根据自己客户端是PC浏览器多还是移动端多,把CHACHA挪后…

 

参考资料:
https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations

spdy 和 http2.0 支持

虽然spdy 协议早已被 HTTP2 取代,但是chrome 旧浏览器和 移动端基于chrome内核的应用还是挺多的,所以spdy 的兼容还是必要的

cloudflare 出了个spdy的补丁,可以兼容HTTP2和SPDY

https://blog.cloudflare.com/open-sourcing-our-nginx-http-2-spdy-code/

靠谱补丁 for nginx 1.10.3:
https://github.com/cujanovic/nginx-http2-spdy-patch/blob/master/nginx-spdy.patch
一般靠谱补丁:
https://github.com/cloudflare/sslconfig/tree/master/patches

打完补丁后, build的时候增加编译参数即可

–with-http_spdy_module #开启spdy 协议, 需要打上cloudflare的patch
–with-http_v2_module #开启HTTP2 协议,不需要任何补丁

nginx 相关配置可以参考nginx 配置文档
server {
listen 443 spdy http2;

}

nginx https 入门配置

nginx 版本选择,一般1.10 或者当前最新stable的1.12都没什么问题

编译参数:

--prefix=/opt/itc/nginx --with-http_ssl_module --with-http_v2_module --with-openssl=../openssl-1.1.0f --with-pcre=../pcre-8.38 --with-zlib=../zlib-1.2.11

其中:
openssl 可以选用1.0版本也可以选用1.1版本,性能会更强,可以在openssl.org下载
pcre zlib都需要自行在对方官网下载
另外, 这两个参数可以按需使用:


--with-openssl-opt=enable-weak-ssl-ciphers #openssl1.1版本开启weak_cipers
--with-http_spdy_module #开启spdy 协议,需要打上cloudflare的patch

配置:

server {
listen 443 spdy http2;
server_name www.4os.org;
root /opt/www/www.4os.org;
access_log logs/www.log main;

ssl_certificate ssl/your_site_key.crt; #公钥
ssl_certificate_key ssl/your_site_key.key; #私钥

ssl_dhparam ssl/dhparams.pem;
ssl_ciphers “ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!RC4:!MD5:!PSK:!aECDH:!DHE”;
ssl_prefer_server_ciphers on;
#ssl_ecdh_curve secp384r1;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

location / {

}
}

cipher_suite 的选择可以参考: https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations

https 支持 IE6和 winXP

winXP + IE6 是非常非常古老的组合, 如果确实需要支持会稍微麻烦些
1. winXP 必须是更新到SP3的,之前的版本无法支持sha2 证书
2. 需要支持TLS_RSA_WITH_3DES_EDE_CBC_SHA 这个属于weak的cipher suite,如果编译的是openssl1.1 版本,则需要编译的时候加入 –with-openssl-opt=enable-weak-ssl-ciphers 参数以开启
3. SNI 不支持,因此IE6只会接收默认的证书,需要把需要支持的域名打到默认证书里边,并且首先加载这个默认虚机 (从测试看,谁先加载谁就是默认证书)
4. 需要开启SSLv3,这是非常不建议的操作
默认的IE6用户设置是没有勾选IE设置里边的TLS1.0的,只支持SSLv2 和 SSLv3