内容来源:工业互联网研发--冯孟 原创
发现问题
在上周一个将要下班的夜晚,小祥突然和我打招呼,说IOS推送修复的更新包上线后存在问题,后台报错。
顿时有点惊慌失措,功能我都是在我自己外网机测试好的,怎么可能出问题!
连忙跑到小祥那里看报错详情,报错如下:
重现问题
看到这个问题后,心里一阵窃喜,这个报错我好像以前遇到过,因为给IOS发推送消息内部是通过给苹果服务器发https消息实现的,Https基于SSL\TLS协议实现的,估计是SSL\TLS协议握手过程中不信任服务端证书导致的,由于不能冒然在线上修改解决问题,于是获取推送相关信息(设备token等)后,到自己电脑上去运行一下,看是否能重现问题。
啪啦啪啦,代码修改完毕,点运行坐等错误出现。
5秒钟过后,发现推送消息发送成功了,没有出现报错,顿时一脸懵!
心里想,代码都是完全一样的啊,怎么线上报错,我这却是好的呢???不应该啊(对小祥说的)
纠结了一会,静下心来看看是否有什么不同
代码肯定是一样的,应该不是代码原因==》其次推送设备是一样的,应该不是手机问题==》那么。。。
扫了一眼工程目录,看到了jdk8,而由你飞线上使用的是jdk7,只有这个不同了。
于是我将自己工程的jdk8换成jdk7试一下,同样的报错终于出现了!
寻找原因
按照之前说的,围绕着以前的经验,这hand_failure应该是SSL\TLS握手过程中不信任服务端证书导致的,办法很简单,去苹果官网找苹果服务端提供的证书,导入到java的证书信任库cacert文件中即可。
啪啦啪啦,下载了证书GeoTrust_Global__CA.cer文件,并用keytool工具导入到了cacert文件中,发现已经有这个证书了,仍然导入 ,再次运行代码,等待问题解决的那一刻。
结果还是报错,怎么办?
怎么办?
心里又慌张起来,自己没招了,接下来只能百度啦,一翻搜索,网上结论几乎都是证书信任问题,和自己的招式一样!
网上了解一翻,SSL\TLS握手过程大约如下:
大致过程是:
客户端发送clientHello消息,告诉服务端我使用的TLS版本与加密套件等。
服务器返回serverHello消息,告诉自己选择哪个TLS协议版本与加密套件等。
服务器发送Certification消息,将自己的数字证书(包括服务器名称、CA和公钥)作为消息内容发给客户端。
客户端Certificate verify校验服务器的数字证书的有效性。
客户端Change cipher spec选择加密套件并生成会话密钥(客户端与服务器之间后续的数据传输将使用此会话密钥)。
客户端、服务器之间发送加密数据。
记得jvm有一个的参数,可以把SSL\TLS的握手过程都在控制台通过日志显示出来。
Ok,既然知道了握手过程,那就把SSL\TLS的日志显示出来看一下吧,看看是什么阶段出现的问题,运行过后日志如下:
如上图,说明GeoTrust_Global.cer证书确实已经添加到信任库中了
如上图,报错发生在clientHello发送之后,在读服务端返回的serverHello消息时,却读到的是警告信息,然后网络就断开了,就好像你在和服务器打招呼,然后服务器回复了一个滚蛋一样!
百思不得其解?
准备放弃
这时看到小祥走过来了
小祥:“问题解决的怎么样了,啥情况啊”
我:“还不知道,本来以为很简单,实际上并没有,jdk8可以,7不行”
小祥:“好吧”
然后小祥就这样回到座位上了。
我也只能默默地继续查找问题原因了,大概过了40分钟吧,感觉已经查不到了,看了看小祥,为了他能早点回家睡觉,我想还是直接升级吧。
我:”要不升级jdk8吧“
小祥:”能行吗“
我:”……能行,jdk都是向前兼容的,要是降级就会有问题,升级一般不会有问题的“
小祥:”……好的“
小祥去升级jdk8了,本来我应该站在小祥身后等待问题被解决,但我还是想在这期间查一查其中原因,于是又琢磨了一翻
发现真相
以前由你飞升级jdk7,就是因为苹果强制开发者必须使用Https,且其中TLS协议要V1.2版本,而jdk7才开始支持==》现在报错会不会…
赶紧使用TLSv1.2试一下,在jvm运行时加参数即可强制https使用TLSv1.2版本协议,加完后运行…
报错依旧,那还有那里可能会有问题呢?
于是我将jdk7运行之后的网络日志与jdk8下运行之后的网络日志拿出来对比看,突然注意到某一点上,即TLS协议的加密套件不同,如下图:
jdk7的调试信息如下 :
jdk8的调试信息如下:
jdk8的TLS握手在服务端ServerHello之后,选择的加密套件是,而jdk7中可供选择的加密套件中没有,问题差不多清晰了,应该是jdk7中的加密套件,苹果服务器觉得太老,都不支持,那么如果我使用jdk8,将加密套件强制使用jdk7中的加密套件呢,应该也是有问题的
于是如下图,在jvm运行时加参数,强制jdk8使用jdk7的加密套件,运行过后,果然报错了
然后去查了一个jdk8的新增特性日志,发现中AES加密算法的GCM模式在jdk8中才支持。
那么问题原因基本全部搞清楚了,小祥升级jdk8后也报告推送正常,此时已是10点多,两人写写日报赶紧回家去了……
领取专属 10元无门槛券
私享最新 技术干货