是否可以删除 Java 中 SSL 握手的扩展部分?
Is it possible to remove the extension part of SSL handshakes in Java?
我正尝试使用 https 连接到旧版 Cisco IPS 服务器。问题是这个服务器只接受特定条件下的握手:
版本必须是TLSv1.0,密码套件必须是SSL_RSA_WITH_RC4_128_MD5或SSL_RSA_WITH_RC4_128_SHA并且不能有任何扩展。
我实现了一个手工制作的 "ClientHello",它发送以下信息作为握手(wireshark 输出):
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 45
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 41
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
服务器发回ServerHello消息。
现在我想使用 Java 的 SSL 实现发送完全相同的 ClientHello。以下代码:
System.setProperty("https.protocols", "TLSv1");
System.setProperty("javax.net.debug", "ssl:handshake");
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("ips-server", 443);
socket.setEnabledProtocols(new String[] {"TLSv1"});
socket.setEnabledCipherSuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
socket.startHandshake();
产生以下握手:
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 52
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 48
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 5
Extension: renegotiation_info
Type: renegotiation_info (0xff01)
Length: 1
Renegotiation Info extension
这会导致服务器发回以下数据包:
TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
是否可以让Java不发送数据包的"extension"部分?
如果有人想知道答案,您需要为 https.protocols 系统 属性 使用 SSLv2Hello。
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
我使用以下代码连接到服务器:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} }, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
编辑 更多解释 -
@EJP 提到这段代码没有回答标题中的问题。我写了一个小测试来显示 SSL client hello 的扩展部分是否被删除作为将 client hello 更改为 SSLv2 的副作用。
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException {
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
String url = "https://www.google.com";
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}}, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Stream<String> lines = br.lines();
lines.forEach(l -> { System.out.println(l);});
}
如果我 运行 这个程序,这就是我在 wireshark 中得到的:
很明显,这实现了我正在寻找的目标:删除 SSL 握手的扩展部分。也许这不是最好的方法,正如@EJP 提到的那样引入了很多安全漏洞(我不关心这里,因为我的 CISCO IPS 服务器是本地的,我只是想连接到它,安全与否),但我不能找到任何其他方法来做到这一点。
我正尝试使用 https 连接到旧版 Cisco IPS 服务器。问题是这个服务器只接受特定条件下的握手:
版本必须是TLSv1.0,密码套件必须是SSL_RSA_WITH_RC4_128_MD5或SSL_RSA_WITH_RC4_128_SHA并且不能有任何扩展。
我实现了一个手工制作的 "ClientHello",它发送以下信息作为握手(wireshark 输出):
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 45
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 41
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
服务器发回ServerHello消息。
现在我想使用 Java 的 SSL 实现发送完全相同的 ClientHello。以下代码:
System.setProperty("https.protocols", "TLSv1");
System.setProperty("javax.net.debug", "ssl:handshake");
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("ips-server", 443);
socket.setEnabledProtocols(new String[] {"TLSv1"});
socket.setEnabledCipherSuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
socket.startHandshake();
产生以下握手:
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 52
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 48
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 5
Extension: renegotiation_info
Type: renegotiation_info (0xff01)
Length: 1
Renegotiation Info extension
这会导致服务器发回以下数据包:
TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
是否可以让Java不发送数据包的"extension"部分?
如果有人想知道答案,您需要为 https.protocols 系统 属性 使用 SSLv2Hello。
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
我使用以下代码连接到服务器:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} }, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
编辑 更多解释 - @EJP 提到这段代码没有回答标题中的问题。我写了一个小测试来显示 SSL client hello 的扩展部分是否被删除作为将 client hello 更改为 SSLv2 的副作用。
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException {
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
String url = "https://www.google.com";
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}}, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Stream<String> lines = br.lines();
lines.forEach(l -> { System.out.println(l);});
}
如果我 运行 这个程序,这就是我在 wireshark 中得到的:
很明显,这实现了我正在寻找的目标:删除 SSL 握手的扩展部分。也许这不是最好的方法,正如@EJP 提到的那样引入了很多安全漏洞(我不关心这里,因为我的 CISCO IPS 服务器是本地的,我只是想连接到它,安全与否),但我不能找到任何其他方法来做到这一点。