最近时间, 偶然发现曾经正常服务的某个 HTTPS 域名无法正常打开, 提示 ERR_SSL_PROTOCOL_ERROR
错误。
问题表现
Chrome 访问特定域名(https) 页面显示系统错误页:
This site can't provide a secure connection
....
ERR_SSL_PROTOCOL_ERROR
排查过程
- 无脑的习惯预判 SSL 证书 过期了 或 忘更新了
搂了一眼, 并不是
- 于是再次习惯性的预判是
nginx
配置问题
查看了下 nginx
的 vhost 站点 ssl 配置, 并无明显问题,
但还是尝试调整了 ssl_protocols
、ssl_ciphers
的设置,然并卵, 依旧无用。
开始觉得问题可能没那么简单了
- 思索了几秒, 判断大概率服务器自身问题了
毕竟是 SSL 错误, 如果 nginx
设置没问题,那么很可能是系统 openssl 版本问题
核查了下系统版本:
$ openssl version -a
OpenSSL 1.0.1e-fips 11 Feb 2013
built on: Thu Nov 6 12:33:36 UTC 2014
platform: linux-x86_64
options: bn(64,64) md2(int) rc4(16x,int) des(idx,cisc,16,int) idea(int) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -m64 -DL_ENDIAN -DTERMIO -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -Wa,--noexecstack -DPURIFY -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
OPENSSLDIR: "/etc/pki/tls"
engines: rdrand dynamic
好像文字也无法描述此时的表情(早期系统的运维很薄弱很随意, so)
于是, 就 自以为是 的决定换上常用的 1.1.1w 版本应该就会好
# 准备 & 下载
cd /usr/local/src
wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xvzf openssl-1.1.1w.tar.gz
# 编译安装
cd openssl-1.1.w
set OPENSSL_HOME=/usr/local/server/openssl-1.1.1w
./config shared \
--openssldir=$OPENSSL_HOME \
--prefix=$OPENSSL_HOME
make && make install
# 备份
mv /usr/bin/openssl /usr/bin/openssl.bak
mv /usr/include/openssl /usr/include/openssl.bak
# 替换
ln -s $OPENSSL_HOME/bin/openssl /usr/bin/openssl
# 注册更新
touch /etc/ld.so.conf.d/openssl.conf
echo "$OPENSSL_HOME/lib" >> /etc/ld.so.conf.d/openssl.conf
ldconfig -v | grep openssl
一顿操作猛如虎, 然而, 奇迹并未发生, WTF ~ 总不能重新编译 nginx 尝试修正吧 ~ 毕竟是生产机器, 上面服务和站点非常多, 不到万不得已先不这么搞(好吧,给自己刨坑了)
- 遂, 祭出搜索大法, 没有什么问题是搜索解决不了的
浑浑噩噩 2B 搬砖的这些年, 虽然还在保持着与时俱进,尽力站在前沿,尽力撑住广度的认知, 但各种不可抗力 以及 可抗(可不抗) 因素也时刻缠绕, 也许我真的已经不是曾经的那个少年了。
发现这个问题出现一段时间了, 但并不久远, 说明可能是某种更新行为引起的。 网上各种说法和解法也是参差不齐,最终我觉得应该是 chrome 搞出来的事。
- 换了个电脑使用 Chrome 访问一切正常
访问正常的 chrome 版本不是最新, 比有问题的 chrome 版本落后了好几个版本。 那么,基本是确定了,是由于 Chrome 更新了跟安全相关的某些功能调整引起的兼容问题。
同时看到一篇文章里提到最终的祸首: Disable SHA1 in TLS server handshakes by default
由于 chrome 的这次更新后, 默认禁用了 TLS 握手时的 SHA1 的加密方式, 但一些 老系统(比如 现在这台)仍旧使用着 低版本 的 openssl, 而 低版本 的 openssl 存在 BUG,会 强制使用 SHA1 那么,问题就是这么产生的了
最简单处理 (掩耳盗铃
), 客户端浏览器修改配置:
把
Allow SHA-1 server signatures in TLS.
的配置项改为Disabled
- 尝试最终修正
话说回来, 一开始就给服务器升级了 openssl
到 1.1.1
, 为什么没作用呢,
想了许久,突然返过味儿来了,毕竟是 nginx
提供的 web 服务, SSL 错误不见得是配置问题,应该是 nginx
的编译配置问题。
于是核查
nginx
编译配置
$ nginx -V
nginx version: nginx/1.6.1
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC)
TLS SNI support enabled
configure arguments: --prefix=/usr/local/server/nginx --error-log-path=/data/log/nginx/error.log --http-log-path=/data/log/nginx/access.log --http-client-body-temp-path=/usr/local/server/nginx/cache/client_temp --http-proxy-temp-path=/usr/local/server/nginx/cache/proxy_temp --http-fastcgi-temp-path=/usr/local/server/nginx/cache/fastcgi_temp --http-uwsgi-temp-path=/usr/local/server/nginx/cache/uwsgi_temp --http-scgi-temp-path=/usr/local/server/nginx/cache/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-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_spdy_module --with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic'
果然, 没有
--with-openssl
配置那么只能重新编译更新了
cd /usr/local/src/nginx1.6.1
./configure \
--prefix=/usr/local/server/nginx \
--error-log-path=/data/log/nginx/error.log \
--http-log-path=/data/log/nginx/access.log \
--http-client-body-temp-path=/usr/local/server/nginx/cache/client_temp \
--http-proxy-temp-path=/usr/local/server/nginx/cache/proxy_temp \
--http-fastcgi-temp-path=/usr/local/server/nginx/cache/fastcgi_temp \
--http-uwsgi-temp-path=/usr/local/server/nginx/cache/uwsgi_temp \
--http-scgi-temp-path=/usr/local/server/nginx/cache/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-mail \
--with-mail_ssl_module \
--with-file-aio \
--with-ipv6 \
--with-http_spdy_module \
--with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' \
# 增加 openssl 源码目录
--with-openssl=/usr/local/src/openssl-1.1.1w
# 仅编译 (不 install)
make
结果, 编译失败!!!
- 修正编译
发现 nginx 与 openssl 也存在一定的 版本匹配问题
nginx 肯定不能随便升级, 那么只能降低 openssl 的版本, nginx 当时编译时依赖的 1.0.1 的 openssl, 那么需要降低到 1.0.x 系列的最新版应该就行 (实际也是如此, 当时这 BUG 也是在 1.0.2 就被官方补丁修正了)
# 重新下载 openssl
cd /usr/local/src
wget --no-check-certificate https://www.openssl.org/source/openssl-1.0.2u.tar.gz
tar -xvzf openssl-1.0.2u.tar.gz
# 重新编译 nginx
cd /usr/local/src/nginx
./configure \
# ...其他参数略
--with-openssl=/usr/local/src/openssl-1.0.2u
# 备份 nginx
cp /usr/local/server/nginx/sbin/nginx /usr/local/server/nginx/sbin/nginx_bak
# 热更 nginx
cd /usr/local/src/nginx
make upgrade
- chrome 浏览器重新访问确认已正常
结束手工