Linux机器上安装的OpenJDK 8不支持ECDHE密码套件 折腾1周了终于完美解决!!!
故事的开始是从对接完臻识的臻云极致平台的mqtt协议后,车牌识别设备通过内置的mqtt客户端连接到臻云后,我们服务端起一个mqtt客户端脸上臻云的mqtt服务器,然后订阅设备发布的消息。
这样一系列操作下来就完成了车牌识别识别到车牌--推送到mqttServer--我们的服务器订阅的频道收到消息中推送的车牌--业务处理之后下发开闸到--mqttServer--设备订阅的频道收到包含指令的消息--执行开闸-屏显-语音等操作。
本来以为到这就结束了,结果一看交易订单发现没图,这咋能行呢!必须把图片搞上!
然而,从接图片开始就进入了一条不归路啊!让我们打开臻识的文档 地址:http://open.vzicloud.com/doc/mqtt/%E4%B8%8B%E8%BD%BD%E5%9B%BE%E7%89%87.html
下载图片
接口描述
针对采用MQTT消息服务上传的识别结果,其图片数据由于数据量太大并不会直接携带在识别结果数据中,而是被推送到云服务器上,利用此接口可以取回图片。
注意:请尽快采用此接口取走图片,服务端会定时清理!
请求说明
协议 方法 PATH HTTPS GET /openapi/v1/${image_path} PATH参数
参数 类型 说明 image_path string 图片路径(在MQTT推送的消息中会携带图片路径,注意需要base64解码) URL参数
参数 类型 必填 说明 accesskey_id string 是 参见签名认证 expires int 是 参见签名认证 signature string 是 参见签名认证 请求示例
GET https://open.vzicloud.com/openapi/v1/imgs/0c067893-556f140f/20200924/1600914068_167485218_3_0_full.jpg?accesskey_id=7eFF9wfE1125qIA05gveauF7wXzt73Ph&expires=1600915909&signature=uGaXPB5HzxpcrBJPUwKwsDl%2BIuo%3D HTTP/1.1Host: open.vzicloud.com注意:您无法将请求示例的链接地址贴入浏览器直接运行,此示例仅展示URL格式,由于AccessKey具备有效期,您访问时此链接已过期。
返回说明
如果签名认证验证通过,会返回一个302重定向,重定向的地址才是图片真正的下载地址,但是需要注意的是,重定向的地址一样具备有效期,超过有效期同样不能访问。
以上的就是他的下载图片的文档
然后咱们的后端小哥哥就开始了对接图片接口的苦逼生涯,一开始写的时候,没啥问题很顺畅,和我前端(就是我自己)联调也没问题。
测得都没啥问题,一致决定择期打包上线
第二天到了,今天是愉快的打包时刻。一切都很正常,咱们的运维小哥(还是我自己)和往常一样,打开了熟悉的IDEA,先点了个重建项目,然后习惯性的点了个运行,看着控制台输出的日志,哇哦!看起来没啥问题,然后迅速的打开了Xshell ,cd 进入目录 做好准备工作。接着他打开了阿里云的负载均衡控制台,只听他口中默念着:把负载打到另一台机,这样应该就不会导致业务中断了。
小哥做好准备工作后机智的往客服那边丢了一句:更新 开始了
小哥是使出了快如疾风的手速,双指在键盘上跳跃。随着屏幕一阵猛烈的刷新,一切都变得索然无味。
只见小哥歪着嘴,依稀听见口中仿佛说着:哎呦,不错呦,好像没啥问题。他接着刚刚的操作,又把另一台服务器更新了。
。。。。。。。
运维小哥把服务器的负载切成了正常状态就观察起了日志。
不对,图去哪了?
奇怪,这个日志怎么到这就没了?有问题,呼唤后端小哥!然后运维小哥就和后端小哥扯起来了
2022-04-19 15:02:40,736 [async-service-2] INFO com.zrxxkj.bluewhale.mqtt.service.FileDownLoadService:66 - 图片下载线程睡眠结束。。。 2022-04-19 15:02:40,812 [async-service-2] INFO com.zrxxkj.bluewhale.mqtt.service.FileDownLoadService:83 - null------------重定向后的地址------------ 2022-04-19 15:02:40,812 [async-service-2] INFO com.zrxxkj.bluewhale.mqtt.service.FileDownLoadService:84 - 文件下载地址为:https://open.vzicloud.com/openapi/v1/imgs/51964fd1-4ed8bc9b/20220419/1650351758_51964fd1-4ed8bc9b_8635_72_full.jpg?expires=1650351818&accesskey_id=KvhYIAnl62y65sHAZTxvc05EKLM6i4hV&signature=TGyFEibFYWsgLl416YsVPWIAia8%3D
欲听后事如何,且看分割线后
最后,开始了长达3天的debug得出一个结论
运维小哥觉得应该是加密套件的问题,后端小哥觉得应该是代码有自己的想法
然后逐一分析:
1、tls用的什么版本?jvm里面有个配置,里面支持1.2不?不支持就放开,本地jvm不支持,也不行,和微信通讯我本地也正常,但是丢服务器就不行,为啥?服务器上不支持那个版本,明白?
2、find -name "java.security"找 jdk.tls.disabledAlgorithms改配置
3、curl可以?直接服务器curl过去也可以,用java调curl
4、带证书发起请求
5、在服务器的jdk中导入对方服务器的证书
以上方法全试过了,都不行,都是在握手时就挂了
找大佬求急救
最后大佬总结 :openjdk难搞,sun的应该还好吧,是JDK不支持ECDHE密码套件上代码测
ServerSocketFactory sslSocketFactory = javax.net.ssl.SSLServerSocketFactory.getDefault(); System.out.println("SSLServerSocketFactory -> " + sslSocketFactory.getClass().getName()); try { Method getSupportedCipherSuitesMethod = sslSocketFactory.getClass().getMethod("getSupportedCipherSuites"); String[] ciphers = (String[]) getSupportedCipherSuitesMethod.invoke(sslSocketFactory); int i=1; for (String c : ciphers) { System.out.println(i++ + " " + c); } } catch(Throwable t) { t.printStackTrace(); }
最后测完发现
本地支持的jdk加密套件列表:
SSLServerSocketFactory -> sun.security.ssl.SSLServerSocketFactoryImpl 1 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 2 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 3 TLS_RSA_WITH_AES_256_CBC_SHA256 4 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 5 TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 6 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 7 TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 8 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 9 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 10 TLS_RSA_WITH_AES_256_CBC_SHA 11 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 12 TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 13 TLS_DHE_RSA_WITH_AES_256_CBC_SHA 14 TLS_DHE_DSS_WITH_AES_256_CBC_SHA 15 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 16 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 17 TLS_RSA_WITH_AES_128_CBC_SHA256 18 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 19 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 20 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 21 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 22 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 23 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 24 TLS_RSA_WITH_AES_128_CBC_SHA 25 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 26 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 27 TLS_DHE_RSA_WITH_AES_128_CBC_SHA 28 TLS_DHE_DSS_WITH_AES_128_CBC_SHA 29 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 30 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 31 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 32 TLS_RSA_WITH_AES_256_GCM_SHA384 33 TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 34 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 35 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 36 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 37 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 38 TLS_RSA_WITH_AES_128_GCM_SHA256 39 TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 40 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 41 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 42 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 43 TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 44 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 45 SSL_RSA_WITH_3DES_EDE_CBC_SHA 46 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 47 TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 48 SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 49 SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA 50 TLS_EMPTY_RENEGOTIATION_INFO_SCSV 51 TLS_DH_anon_WITH_AES_256_GCM_SHA384 52 TLS_DH_anon
linux服务器支持的jdk加密套件列表:
果然服务器中并没有TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256这个加密算法
苦逼的运维小哥开始疯狂寻找如何在openjdk中支持TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256的方法
走了很多弯路,终于解决了
解决方法:
添加bouncycastle作为算法提供程序
去这里下扩展包 https://www.bouncycastle.org/latest_releases.html
红色框里面圈起来的就是
接着把包导入到jre中 :
添加bcprov-<verion>.jar到/usr/lib/jvm/jre/lib/ext 编辑/usr/lib/jvm/jre/lib/security/java.security
将以下行添加到提供程序列表中:
重启服务器,哇偶!问题解决了!