无法在Spring应用程序中创建安全的WebSocket

时间:2019-07-29 08:47:39

标签: spring websocket certificate

我有一个spring-boot应用程序,我试图打开与服务器的安全websocket连接,但是由于以下原因,我不断收到错误消息:没有主题替代名称。

这是我尝试过的:

StandardWebSocketClient client = new StandardWebSocketClient();
SSLContext sslContext = this.getSslContext("path/to/truststore", "path/to/keystore.p12", "password");
client.getUserProperties().put(SSL_CONTEXT_PROPERTY, sslContext);
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
headers.add("Sec-WebSocket-Key", "SGVsbG8sIHdvcmxkIQ==");
headers.add("Origin", "https://192.168.1.132:8445");
headers.add("Sec-WebSocket-Version", "13");
String url = "wss://192.168.1.132:8445/websocket";
URI uri = new URI(url);
ListenableFuture<WebSocketSession> future = client.doHandshake(new AbstractWebSocketHandler() {
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        receivedMessages += message.getPayload();
        System.out.println(message.getPayload());
    }
}, headers, uri);
WebSocketSession socketSession = future.get();

这是getSslContext方法:

private SSLContext getSslContext(String trustStoreFile, String keystoreFile, String password)
        throws GeneralSecurityException, IOException {
    KeyStore keystore = KeyStore.getInstance("JKS");
    try (InputStream in = new FileInputStream(keystoreFile)) {
        keystore.load(in, password.toCharArray());
    }
    try (InputStream in = new FileInputStream(trustStoreFile)) {
        keystore.load(in, password.toCharArray());
    }

    KeyManagerFactory keyManagerFactory =
            KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keystore, password.toCharArray());

    TrustManagerFactory trustManagerFactory =
            TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keystore);

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(
            keyManagerFactory.getKeyManagers(),
            trustManagerFactory.getTrustManagers(),
            new SecureRandom());

    return sslContext;
}

鉴于此代码,我总是遇到以下错误:

Caused by: java.security.cert.CertificateException: No subject alternative names present
    at java.base/sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:141)
    at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:100)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:429)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:283)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1302)

我还尝试使用以下curl命令复制请求:

curl --include --no-buffer --header "Connection: Upgrade" --header "Upgrade: websocket" --header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" --header "Origin: https://192.168.1.132:8445" --header "Sec-WebSocket-Version: 13" -Ss --cacert myCA.pem --cert SSLCert.pem:`cat SSLCert.pass` https://192.168.1.132:8445/websocket

握手似乎成功:

HTTP/1.1 101
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: panel-command-server:default,postgres,cassandra,kafka:8080
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: qGEgH3En71di5rrssAZTmtRTyFk=

任何想法都可能是什么原因导致spring申请中没有主题替代名称出现错误?

1 个答案:

答案 0 :(得分:2)

设法通过覆盖信任管理器中的某些方法来绕过检查,以解决此问题,例如:How to bypass ssl certificate checking in java

这是我使用的getSslContext的最终版本:

onValueChange(newValue) {
        this.item.key1 = null;
        setTimeout(() => {
            console.log('Initial: ' + newValue);

            if (newValue.length > 4) {
                newValue = newValue.substring(0, 4);
            }
            console.log('Final: ' + newValue);

            this.item.key1 = newValue;
        })
    }