RC4被JDK8默认禁用导致腾讯QQ邮箱无法访问
7月29日开始,腾讯修改了邮箱的加密方式,导致我们线上的所有的腾讯代收、代发邮件的功能全部失效。解决方法在最后,如果需要可直接跳转至解决方法一节
问题出现
7月29日开始,线上的所有的腾讯代收、代发邮件的功能全部失效,报handshake_error
:
1 | javax.mail.MessagingException: Connect failed; |
记得当时用客户端链接腾讯的企业邮箱时,报证书警告,警告原因是pop.exmail.qq.com
这个域名使用了pop.qq.com
这个证书,应该是为了省钱吧。但是当用QQ个人邮箱连接的时候,确实使用了正确的证书,那错误原因应该不同。
问题定位
把问题交给做邮箱连接的同事,结果同事很快告诉我,他在windows上运行代码完全没有任何问题,并且JDK都用了相同的版本:1.8.0_u60。难道这个错误和系统相关?
打开Thunderbird尝试连接腾讯邮箱,发现一切也正常。可以断定这个问题不是系统相关的,问题一定出在我们的代码中。网上搜了一些handshake_failure
相关的原因如下(StackOverflow):
- Incompatible cipher suites in use by the client and the server. This would require the client to use (or enable) a cipher suite that is supported by the server.
- Incompatible versions of SSL in use (the server might accept only TLS v1, while the client is capable of only using SSL v3). Again, the client might have to ensure that it uses a compatible version of the SSL/TLS protocol.
- Incomplete trust path for the server certificate; the server’s certificate is probably not trusted by the client. This would usually result in a more verbose error, but it is quite possible. Usually the fix is to import the server’s CA certificate into the client’s trust store.
- The cerificate is issued for a different domain. Again, this would have resulted in a more verbose message, but I’ll state the fix here in case this is the cause. The resolution in this case would be get the server (it does not appear to be yours) to use the correct certificate.
问题来了,如果以上是问题所在的话,一定会有一些错误信息输出,但为什么在我的系统中没有任何输出?
想到telnet,因为一般测试邮箱连接都直接使用telnet明文测试一下。当然这个想法是不可行的,如下:
1 | fify@fify-PC:~$ telnet pop.qq.com 995 |
没有办法输入任何东西,原因也很简单,995端口使用了加密。(这里犯迷糊了,现在握手错误就是因为加密问题…)
换一个方式连接POP邮箱:
1 | openssl s_client -connect pop.qq.com:995 |
输出如下:
1 | CONNECTED(00000003) |
注意到以下片段
SSL-Session:
Protocol : TLSv1.2
Cipher : RC4-SHA
可以看到,加密使用的协议是TLSv1.2
,Cipher使用的是RC4-SHA
。
那么问题是出在这两个地方吗?
JavaMail握手时的Protocol和Cipher
在Java启动中增加参数-Djavax.net.debug=all
可以开启加密协议的调试模式。详情可以参考Oracle提供的文档。
开启之后,连接邮箱握手的过程中打出了以下日志:
1 | trigger seeding of SecureRandom |
注意到:
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
发现其中果然没有RC4
相关的Cipher Suites。
在同事Windows机器上试了以下,输入果然不同,如下:
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
赫然发现:SSL_RSA_WITH_RC4_128_SHA。这正是我们想要的东西。
解决问题
问题找到了,解决办法应该也比较容易找到。查看POP协议相关的所有参数,找到了mail.pop3.ssl.ciphersuites
。在JavaMail的Properties中增加相关的SSL_RSA_WITH_RC4_128_SHA
:
1 | prop.setProperties("mail.pop3s.ssl.ciphersuites", "SSL_RSA_WITH_RC4_128_SHA"); |
重启服务器,测试,一气呵成,结果:handshake_failure
还是系统问题?
以SSL_RSA_WITH_RC4_128_SHA
为关键字搜索,搜到了这篇文章:Java 8 update 60 disables “RC4” cipher suites: Causes issues with Blancco erasure software and MC 3 communication。这是别的软件遇到的问题,但原因是一样的。
原来从JDK 1.8.0_u60开始,默认禁止了RC4这个算法。可以在{JRE_HOME}/lib/security/java.security
找到相关配置:
534 jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 768
以及
586 jdk.tls.legacyAlgorithms=
587 K_NULL, C_NULL, M_NULL,
588 DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT,
589 DH_RSA_EXPORT, RSA_EXPORT,
590 DH_anon, ECDH_anon,
591 RC4_128, RC4_40, DES_CBC, DES40_CBC
那Windows中同样的JDK版本,为什么却可以正常使用呢?比较发现在Windows安装之后的Java目录中,有两个部分,一个是JDK目录(其中包含一个JRE目录),一个是直接的JRE目录。打开两个java.security
文件,惊奇的发现两个文件并不相同,JRE目录中的java.security
并不包含禁用RC4算法这些配置。
解决方法
启用Java的RC4算法
没有去深研究为什么JDK会默认禁止这个算法,也不知道腾讯为什么会重新选择了一个JDK默认禁用的算法(7月29日之前是没有问题的)。但由于需要用到QQ邮箱,所以必须得开启这个算法。开启步骤如下:
- Go to the Java JRE installation folder: {JRE_HOME}\lib\security\
- Locate java.security file.
- Make a backup copy of the file.
- Edit the java.security file with a text editor software (for example Notepad) according to the example further below.
1 | 534c534 |
启用协议
在POP/SMTP的协议中增加最新的TLSv1.2协议:
1 | prop.setProperties("mail.pop3s.ssl.protocols", "TSLv1 TSLv1.1 TLSv1.2"); |
或
1 | prop.setProperties("mail.smtps.ssl.protocols", "TSLv1 TSLv1.1 TLSv1.2"); |
启用Cipher Scites
因为我需要兼容的不只是RC4这个算法,所以我启用了大部分的Cipher Suites
1 | prop.setProperties("mail.pop3s.ssl.ciphersuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA SSL_RSA_WITH_RC4_128_SHA TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLS_ECDH_RSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_RC4_128_MD5 TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); |
或
1 | prop.setProperties("mail.smtps.ssl.ciphersuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA SSL_RSA_WITH_RC4_128_SHA TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLS_ECDH_RSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_RC4_128_MD5 TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); |
转载请注明出处:RC4被JDK8默认禁用导致腾讯QQ邮箱无法访问
原文地址:https://www.xiaotanzhu.com/java/2016-07-30-use-rc4-in-tencent-mail.html