数据传输需要安全的HTTPS,所以我们用了自签的CA证书

数据安全现在越来越多的被各个公司所重视起来,甚至有从业人员因为信息泄漏而直接丧失人生自由的。 所以,“安全”对于某些公司已经到了一个歇斯底里的地步了。这里不讨论这样重视“安全”的意识是否正确, 但为了安全而“安全”的做法,很多时候真的让人觉得哭笑不得,甚至让人抓狂。

故事的背景

最近由于种种奇怪的原因,被抓去调试某个第三方系统的接口这种本不应该在我职责范围内的工作。本着和同僚 使用习惯能够兼容的情况,就按照他们的习惯使用了Java的OkHttp客户端。当然,第三方的接口文档也不可能是 类似鹅厂那样的完整,(虽然说鹅厂文档也各种坑,但至少内容还是比较扎实,设计还是比较有规范的)。 因此,拿到的数据文档只能说是将就够看,所谓的接口也是各种的问题,与其说是第三方API接口,更像是把 前端界面的接口的文档整理一下拿来应付的。然而文档的问题,在这个故事只能是一笔带过不值一提,关键的问题是, 调试及对接的服务器,居然是采用自签名CA证书的https链接。而这个自签CA证书的https就是故事中噩梦的开始。

自签CA的https只是开始

拿到同僚给的服务器信息,第一眼就看到了协议是https的,心中瞬间飘过了一丝不详的预感。因为根据经验以及 第三方厂商这个文档的情况,有很大的可能这个站点的CA证书是自签的,于是测试请求了一下,果然是自签证书。 但还记得一开始说过的,为了迎合同僚的习惯,我使用了OkHttp的客户端吗?所以,为了关闭自签证书的验证, 不得不修改默认客户端的配置信息。

但想到既然同僚们说自己习惯用OkHttp那这种低级的问题应该已经有现成的解决手法了吧,所以就随便问了一下。 不过,让我感到无语的是,同僚反问我一句:https是啥?以前没遇到过https的接口啊,我们一直用的都是http。 既然如此,网上查一下再看一下OkHttp的文档,配置一下客户端对证书的验证,应该就能绕过了吧。虽然有些麻烦, 但毕竟能连上了。这里顺带一体,OkHttp是用Kotlin开发的,由于某些原因,我却只能用Java实现功能。

按照网上的文档,以及官方的API文档说明,配置好客户端。最初,是打算把那张CA证书加入到OkHttp受信证书 的列表里的,但那样做太麻烦了,所以最后决定还是直接忽略证书的校验。在一通编译后,我信心满满的执行了程序, 请求远程的服务器。

绕过证书验证就结束了吗?

事实证明,我还是高估了这个服务器的情况。在绕过证书请求服务器后,请求依旧报错。一开始我以为是我绕过证书 的配置有问题,但经过检查发现这个配置没有问题。随后就只能在服务器的请求上找原因了。这不查不知道, 一查我背后一身冷汗。为啥?还记得之前我第一个方案是要将这张自签的CA证书加到受信证书里的事情吗?最后, 因为觉得太麻烦所以就直接忽略所有证书了。幸亏当时偷懒,不然我估计还要再做一段无用功。因为这张可笑的自签CA, 居然是一张已经过期的CA证书,而且至少过期5年以上。如果当时采用第一个方案,估计证书验证还是过不了。

那么,问题的症结到底是什么呢?根据错误信息的提示,服务器选择采用TLSv1.0的协议和我进行通信。我当时的第一反映 是怀疑我看错了,但几经确认,证明我确实没有看错。在这个年代,居然还能有只支持1.0协议的https服务器。其实, 本身他的提示是TLSv1协议,那或许1.0 1.2 1.3都囊括其中呢?然而,经过curl的测试,发现服务器只能选择 1.0的协议与客户端通讯。看来这台服务器比较专一。此时我依旧本着和同僚保持一致的想法继续想在OkHttp上做文章, 既然默认不支持,那配置一下让他支持不就好了吗?毕竟证书都绕过了,难道链接还绕不过吗?

0.1的差距不只是版本号的区别

试用了网上的各种奇技淫巧的操作后,最终证明了,我还是太低估了这个问题的严重性。1.0和1.1不只是一个版本号的 区别,更多的是加密认证算法的差异。1.1协议的很多加密算法,1.0都无法支持,而OkHttp在配置完生成链接的时候, 会设置加密算法以保证请求的安全。因此,不论你如何修改,采用TLSv1.0,必然会出错。最后,看到一篇旧文中提到, 把OkHttp的版本换成老版本就能解决问题了。抱歉,这就好像在门背后拉屎一样的幼稚,暂且不论同僚的代码是否能支持 这个上古的旧版本,不要忘了,采用这个坑爹的https,就是为了安全,既然如此怎么可能允许用一个老的存在“漏洞”的 版本。此时,在我经历了各种思考之后,我决定还是放弃和那些同僚采用兼容的解决方案,采用我自己的方式去解决问题。

身心疲惫之后的同僚补刀

俗话说,不怕神一样的对手,只怕猪一样的队友。一开始采用OkHttp的是那些同僚,最后却是解决个常见https自签CA的问题, 都没有经验。甚至,有一个自称很懂技术的人在知道这个情况后,还反问了我一句“官方文档哪里明确说了不支持TLSv1.0吗”。 说实话,说这句话的人纯粹是站在想当然的立场上讲出这种论调。如果文档上写了,怎么可能会绕这么一圈,更重要的是, 对于开发OkHttp的团队而言,他们怎么可能会预见到如今还会有只支持TLSv1.0这种上古协议的服务器。不得不承认,这位 之前还理直气壮的透露出对HTTP协议一无所知的同僚,现在能说出这种话来也是在他的能力范围内的。但在经历过以上这些 后,听到这样的提问实在让人觉得一种无奈。

安全对于这些官僚主义者只是形式

其实,采用https的目的是为了防止http数据明文传输造成的信息泄漏和篡改。这对于信息安全是无可厚非的,而且,对于 某些厂商或者团队来说,部署一张受信的CA证书也许确实是有些困难。而且,“外国人都是洪水猛兽,我们不能在我们的服务器 上部署免费的SSL证书,这样会有安全问题“。但你部署一张过期的CA证书,而且还强制使用TLSv1.0协议,这也能被称为是安全吗? 本来自签的证书就容易遭到中间人攻击,再加上你还用存在安全隐患的1.0协议。其实,这只能用一个原因来说名问题, 那就是不愿意花成本,又想要信息安全。最后,只能在成本和安全中间,走一个形式。而这个形式,有让使用的人觉得无比的抓狂, 最后形式终究还是只是形式,并不能起到他应有的作用。

最后,原本这个预计一天能测试通过的接口,整整浪费掉我2,3天的时间。自签过期CA+安全隐患TLSv1.0协议。 这些所谓的场面安全,只是增加正经使用服务的应用的门槛和难度,对于想要破坏的人来说,并没有多大的差别。 这种安全策略真是滑稽可笑。