首页 > 解决方案 > Android:对于套接字,传递“对等方的证书与预期的主机名不匹配”错误的最安全方法?

问题描述

概括:

当我们收到“对等方的证书与预期的主机名不匹配”错误时,如何使用通配符证书创建到服务器的套接字?


基本上,我想为具有通配符证书的服务器创建一个安全的 websocket (wss)。我正在使用这个 websocket 库。现在,当我想连接到网站时,连接会立即关闭,并显示以下错误日志:

2021-03-16 13:14:16.221 21027-21097/com .....app W/System.err: com.neovisionaries.ws.client.HostnameUnverifiedException: 对等方的证书与预期的主机名不匹配 (sthsth .sthsth.ir) 2021-03-16 13:14:16.221 21027-21097/com .....app W/System.err: at com.neovisionaries.ws.client.SocketConnector.verifyHostname(SocketConnector.java:281 ) 2021-03-16 13:14:16.222 21027-21097/com .....app W/System.err: at com.neovisionaries.ws.client.SocketConnector.doConnect(SocketConnector.java:246) 2021-03 -16 13:14:16.222 21027-21097/com .....app W/System.err: at com.neovisionaries.ws.client.SocketConnector.connect(SocketConnector.java:190) 2021-03-16 13: 14:16.222 21027-21097/com.....app W/System.err: at com.neovisionaries.ws.client.WebSocket.connect(WebSocket.java:2351) 2021-03-16 13:14:16.223 21027 -21097/com .....app W/System.err:在 com .....app.network.GeneralSocketService$1.run(GeneralSocketService.java:167)

2021-03-16 13:14:15.895 21027-21097/com .....app E/Conscrypt: ------------------不受信任的链:---- ------------------ 2021-03-16 13:14:15.896 21027-21097/com .....app E/Conscrypt: == Chain0 == 版本: 3 2021-03-16 13:14:15.897 21027-21097/com .....app E/Conscrypt:序列号:e63f80cf7a1220146cc8fd96d8468a4 2021-03-16 13:14:15.900 21027-21097/com ..... app E/Conscrypt: SubjectDN: CN=*.sthsthnet.ir, C=US 2021-03-16 13:14:15.908 21027-21097/com.....app E/Conscrypt: IssuerDN: CN=Certum Domain Validation CA SHA2,OU=Certum 证书颁发机构,O=Unizeto Technologies SA,C=PL 2021-03-16 13:14:15.914 21027-21097/com .....app E/Conscrypt:不要早于:7 月 30 日星期二10:35:53 GMT+04:30 2019 2021-03-16 13:14:15.916 21027-21097/com .....app E/Conscrypt:不要迟到:7 月 29 日星期四 10:35:53 GMT+ 2021 年 04:30 2021-03-16 13:14:15。918 21027-21097/com .....app E/Conscrypt:Sig ALG 名称:SHA256withRSA 2021-03-16 13:14:15.921 21027-21097/com .....app E/Conscrypt:签名:
22bc2d40a15e881292c19f5b47ca610cc3efb90e998b7eddf08ab108f56ec3df1b7ea7f2ac25b8df74cc49735f3fe7f509fe87ea42c080424f450f8f1bf04a35e4c97dac79ee2df66cde96f4a7a1fb6b62f5640f0a111a157feb7ef5ceab2588cad1731bbf22434d2ee3e0fcbec8ff74ad194d0c2a5ab113b4d00302e62721052b7d0afacc6cda129c3ff99db165d3836a1e2900dd66f8eb3b05f4aab6f42de2a85a60c5382d8bf229c3b866a662326606444685f62673cfbe5fd6a4dc21aa8b18e36c9e13423917aabf79b817011a757262f7b16629745a44162eb9a58ebab4adeefb4710a439f34844b0489f44d3afe​​0a1ba2e0f78dd5fc04009b0096e1837 2021-03-16 13:14:16.213 21027-21097/com.....app E/Conscrypt: Public key:

 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03
 82 01 0f 00 30 82 01 0a 02 82 01 01 00 9d b2 14 d0 11 c4 8f
 29 42 7a ee 09 1e 30 2e 62 dd 14 b8 6b 7b 1b 6b fe 03 ba 6a
 07 6b 6c 69 b3 07 58 51 cf c0 4c 67 15 7e 0f 46 45 33 2b f5
 50 20 db 2c 45 f7 8a 52 29 d2 a0 10 65 31 1d 9f d9 90 2f 83
 e9 d7 c1 ee 1a a6 e8 47 3d 89 fb 8b cf d0 d7 7f ac de d1 39
 ec 4b 8d 43 a4 d5 c2 95 e4 ab 4e 6e 2b a6 b7 24 f7 62 1b 3e
 4a 27 ca a0 d7 9f 22 c3 25 d8 bd 54 39 27 51 99 d5 fa 13 ed
 88 8a 64 9c ce 60 38 ae ea 7e 5f ee ed b1 ff cf 30 56 6d 5c
 01 ad 0c d8 87 f0 4f c7 89 85 e0 d1 08 89 e8 69 dc 6e 35 c0
 7d fc e6 37 33 00 a9 c8 7b 88 9e eb 98 02 bc 6c 9c f4 b7 6b
 87 ca 15 1d 31 37 95 07 8e d2 c8 6a db 92 e0 93 35 4b f8 b0
 29 b9 8f 21 d8 70 0a 5d 91 c5 fb 9c 51 b2 3e a8 6e 53 78 64
 5c e5 c3 06 02 ab e5 0e 11 96 ea a9 f4 99 ea f2 66 d2 c2 6b
 86 eb 90 0d f1 85 3f ef 51 02 03 01 00 01

现在使用我知道使用:

WebSocketFactory.setVerifyHostname(false);

导致另一个错误,我不想更改我的代码,因此它会验证各种证书或自签名证书,如下所示:

TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
}};

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());
factory.setSSLContext(sslContext);
socket = factory.createSocket(API_SOCKET);TooTallNate/Java-WebSockethttps://github.comTooTallNate/Java-WebSockethttps://github.com

也不是这个:

SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
                    factory.setSSLContext(sslContext);
                    socket = factory.createSocket(API_SOCKET);

我也不想在我的应用程序中存储服务器的证书,因为它可能会不时更改并且维护会失控:

    //1. Get the cert file from the server 
    //2. Converted the cert to a BKS format
    
    
     // loading CAs from an InputStream 
CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
InputStream cert = context.getResources().openRawResource(R.raw.my_cert); 
Certificate ca;
 try {
 ca = cf.generateCertificate(cert);
 } finally {
 cert.close();
 } 
// creating a KeyStore containing our trusted CAs 
String keyStoreType = KeyStore.getDefaultType(); 
KeyStore keyStore = KeyStore.getInstance(keyStoreType); 
keyStore.load(null, null); 
keyStore.setCertificateEntry("ca", ca); 
// creating a TrustManager that trusts the CAs in our KeyStore 
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 
tmf.init(keyStore); 
// creating an SSLSocketFactory that uses our TrustManager 
SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(null, tmf.getTrustManagers(), null); 

是否有另一种解决方案可以在不影响安全性或维护性的情况下仅通过主机验证问题?

标签: javaandroidwebsocketssl-certificatewildcard

解决方案


之前有同样的问题,发现大公司签署的证书是受设备信任的,所以当其他人试图制作自己的证书时非常危险,因为(在这种情况下)android无法确定,你的数据是加密良好

您要么应该拥有正确的证书,要么应该信任它们。第二种解决方案对于开发来说是可以的,但绝不应该在生产中使用


推荐阅读