java - 是否可以删除 Java 中 SSL 握手的扩展部分?

标签 java ssl https handshake jsse

有一个旧的 Cisco IPS 服务器,我正在尝试使用 https 连接到它。问题是这个服务器只接受特定条件下的握手:

版本必须是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 发送数据包的“扩展”部分?

最佳答案

如果有人想知道答案,您需要为 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 中得到的: enter image description here

如果我注释掉 SSLv2Client 部分,我会得到: enter image description here

很明显,这实现了我一直在寻找的目标:删除 SSL 握手的扩展部分。也许这不是最好的方法,正如@EJP 提到的那样引入了很多安全漏洞(我不关心这里,因为我的 CISCO IPS 服务器是本地的,我只是想连接到它,安全与否),但我不能找到任何其他方法来做到这一点。

关于java - 是否可以删除 Java 中 SSL 握手的扩展部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36743554/

相关文章:

java - 如果在 Websphere 8.5 中启用了 SSL,则无法查找

shell - 使用 shell 和 curl 检查站点是否可用以进行 https URL 重定向

linux - 如何从命令行测试 HTTPS rest

java - 是否有 unix 纪元毫秒的 DateTimeFormatter?

java - 用字符串终止循环。 ( java )

java - Controller 外部的 Spring 异常处理程序

java - Android 应用程序架构——基于事件或分层

java - 建立 SSL 主机连接时无法使用签名证书验证 Cacerts

python - pip:证书失败,但 curl 有效

azure - 如何信任 Azure Web 应用程序中的 Active Directory 根 CA 证书?