我正在通过Tomcat 8 + Java 8构建B2B服务。 但我的一位客户无法使用SSL连接到我的服务。 添加SSL调试参数后:" -Djavax.net.debug = ssl",我看到错误消息:
Is initial handshake: true
Is secure renegotiation: false
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
https-jsse-nio-8445-exec-9, READ: SSLv3 Handshake, length = 62
*** ClientHello, TLSv1
RandomCookie: GMT: 1490342314 bytes = { 192, 161, 228, 31, 66, 175, 222, 13, 79, 128, 217, 81, 18, 152, 169, 58, 114, 35, 201, 201, 147, 74, 131, 2, 213, 145, 181, 76 }
Session ID: {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, Unknown 0xff:0x3, SSL_RSA_WITH_RC4_128_MD5]
Compression Methods: { 0 }
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Initialized: [Session-7, SSL_NULL_WITH_NULL_NULL]
https-jsse-nio-8445-exec-9, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
如何解决错误?
答案 0 :(得分:0)
以下是我分享解决问题的经验。
启用SSL调试参数&#34; -Djavax.net.debug = ssl&#34;,发现错误为&#34;没有共同的密码套件&#34;
在搜索了一些页面之后,我安装了#Java; Java密码术扩展(JCE)无限强度管辖权&#34;,http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html,它在JVM级别添加了一些加密算法,例如:TLS_RSA_WITH_AES_256_CBC_SHA,但是它没有解决问题。 PS。 Ciphers.java是一个有用的代码,可以在JVM级别显示可用的密码套件。
我捕获了网络数据包并在wireshark中进行了分析,它显示客户端发送ClientHello后,我的服务器立即断开连接。
由于我的客户无法通过我的测试,我必须自己重现问题,以加快故障排除过程。然后我找到了代码SslPoke.java并对其进行了修改。它可以通过使用TLS版本或密码套件的不同组合来模拟客户端的请求。而且我可以自己模拟相同的错误日志,它有很多帮助。
然后,再次google,我发现我可以在Tomcat的server.xml中指定密码套件,例如:
<Connector port="${https.port}" SSLEnabled="true" scheme="https" sslProtocol="TLS" ciphers="TLS_RSA_WITH_AES_256_CBC_SHA256... " />
我添加了配置,由SslPoke测试并通过,案例已关闭。
希望这种体验可以帮助那些面临同样问题的人。 别忘了检查JVM / Web容器/应用服务器中的密码套件配置... 以下代码也非常有用,感谢提供它们的专家。
最诚挚的问候,
利昂
代码:Ciphers.java,来自:https://confluence.atlassian.com/bitbucketserverkb/list-ciphers-used-by-jvm-779171661.html
public class Ciphers
{
public static void main(String[] args)
throws Exception
{
SSLServerSocketFactory ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
String[] defaultCiphers = ssf.getDefaultCipherSuites();
String[] availableCiphers = ssf.getSupportedCipherSuites();
TreeMap ciphers = new TreeMap();
for(int i=0; i<availableCiphers.length; ++i )
ciphers.put(availableCiphers[i], Boolean.FALSE);
for(int i=0; i<defaultCiphers.length; ++i )
ciphers.put(defaultCiphers[i], Boolean.TRUE);
System.out.println("Default\tCipher");
for(Iterator i = ciphers.entrySet().iterator(); i.hasNext(); ) {
Map.Entry cipher=(Map.Entry)i.next();
if(Boolean.TRUE.equals(cipher.getValue()))
System.out.print('*');
else
System.out.print(' ');
System.out.print('\t');
System.out.println(cipher.getKey());
}
}
}
代码:SslPoke.java,来自:https://gist.github.com/4ndrej/4547029
public class SslPoke {
private static javax.net.ssl.SSLSocketFactory getFactorySimple() throws Exception {
SSLContext context = SSLContext.getInstance("TLSv1");
context.init(null, null, null);
return context.getSocketFactory();
}
public static void main(String[] args) {
System.getProperties().setProperty("javax.net.debug", "ssl");
System.getProperties().setProperty("https.cipherSuites", "TLS_RSA_WITH_AES_256_CBC_SHA");
try {
String urlStr ="https://<your host>:<your port>";
URL url = new URL(urlStr);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
javax.net.ssl.SSLSocketFactory sslSocketFactory = getFactorySimple();
connection.setSSLSocketFactory(sslSocketFactory);
InputStream in = connection.getInputStream();
while (in.available() > 0) {
System.out.print(in.read());
}
System.out.println("Successfully connected");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}