某一天,我在使用 docker 的时候遇到个奇怪的问题,在容器里面发起 https 请求报了个错。 经过测试发现在容器里面发起的所有 https 请求都报错,即使是 curl 发起 https 请求也报错。 而 http 请求却能正常发起请求。
# curl https://www.qq.com
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
从测试结果大致可以看出是证书的问题。 经过一系列 google 查询、chatgpt咨询、线下咨询运维大佬等都没能找到问题的正确原因。
只知道是证书问题,因此尝试过很多办法。 比如在 docker 打包的时候找一个正确的根证书(网上下载)打包进去 比如在打包的时候在基础镜像中执行安装根证书包的命令等等。
然而,都没有解决
。
由于折腾了各种办法都解决不了,于是就暂时放弃下班了。
只是思来想去还是不甘心,于是第二天早上一大早到公司之后又进入容器里面去折腾了下。
此时,神奇的事情发生了,当我在容器里面习惯性 curl https://www.qq.com
的时候发现竟然通了。
仔仔细细回想了下,没做啥特殊操作,也没改代码,当时就给我震惊了。 然后,和前一天一样,又查了很久,同样的也没找到它恢复的原因。
直到下午,开发另一个需求的时候为了方便调试,我执行了 w2 proxy
,对接口请求做了代理。
由于那个 https 请求的奇怪问题一直困扰着,于是在做需求的间隙又习惯性回来测试,竟然发现容器里面又不能发起 https 请求了。
因为以前因为设置代理遇到过类似的相关网络问题,于是,大胆怀疑,就是这个代理导致的。
后经过一番代理的打开和关闭测试与验证。
石锤了就是因为开了 whistle 代理才导致在容器内部发起不了 https 的
。
那么 whistle 是如何影响到容器的 https 请求的呢?
curl -v -s -o /dev/null https://www.qq.com
# or
curl -vvvv https://www.qq.com
curl -vvvv 是 curl 命令的一个选项,用于启用最高级别的详细输出。 每个 v 代表一个级别的详细程度,因此 -vvvv 表示启用四个级别的详细输出。 curl -vvvv 会输出包括请求和响应的各种详细信息,如请求头、响应头、TLS 握手信息等。
上图圈选部分的信息就是关键错误信息。
将其交给 chatgpt 分析一下:
从上面的回答只能看出是证书的问题,但是具体怎么解决却没有办法。 也无法知晓 whistle 代理具体是如何导致错误的。
根据现象找原因还是有很多办法的,openssl 命令可以很方便的查到证书链信息。
openssl s_client -connect www.qq.com:443
openssl s_client -connect 是一个 OpenSSL 命令。 该命令用于建立与指定主机和端口的 SSL/TLS 连接,并提供与链接相关的详细信息。 可以用来验证服务器端证书链的完整性、确认所使用的协议和加密套件、检查证书的有效期等。
该命令执行以下操作:
建立 SSL/TLS 连接:通过指定主机和端口,openssl s_client 命令会尝试与该主机建立 SSL/TLS 连接。
显示证书链信息:命令会显示服务器端发送的证书链信息,包括证书的颁发机构、有效期、公钥等。
显示协议和加密套件信息:命令会显示所使用的 SSL/TLS 协议版本以及加密套件的详细信息。
提供调试和故障排除信息:openssl s_client 命令会输出与 SSL/TLS 握手过程相关的详细信息,包括握手协议、密钥交换、证书验证等。
从上图可以很清楚的看到 whistle 的证书成为了 https 请求证书链的一个环节。 而由于他的证书并不是正规的官方系统信任的证书,因此出现上面的问题也就不奇怪了。