java - 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:签名:
22bc2d40a15e881292c19f5b47ca610cc3efb90e998b7eddf08ab108f56ec3df1b7ea7f2ac25b8df74cc49735f3fe7f509fe87ea42c080424f450f8f1bf04a35e4c97dac79ee2df66cde96f4a7a1fb6b62f5640f0a111a157feb7ef5ceab2588cad1731bbf22434d2ee3e0fcbec8ff74ad194d0c2a5ab113b4d00302e62721052b7d0afacc6cda129c3ff99db165d3836a1e2900dd66f8eb3b05f4aab6f42de2a85a60c5382d8bf229c3b866a662326606444685f62673cfbe5fd6a4dc21aa8b18e36c9e13423917aabf79b817011a757262f7b16629745a44162eb9a58ebab4adeefb4710a439f34844b0489f44d3afe0a1ba2e0f78dd5fc04009b0096e1837 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);
是否有另一种解决方案可以在不影响安全性或维护性的情况下仅通过主机验证问题?
解决方案
之前有同样的问题,发现大公司签署的证书是受设备信任的,所以当其他人试图制作自己的证书时非常危险,因为(在这种情况下)android无法确定,你的数据是加密良好
您要么应该拥有正确的证书,要么应该信任它们。第二种解决方案对于开发来说是可以的,但绝不应该在生产中使用
推荐阅读
- javascript - 在使用它们进行导航的网站上禁用左右箭头 (duckDuckGo)
- c++11 - 仅定义默认构造函数时接受构造函数参数的专用模板
- sql - 如何在 Presto 的 varchar 字段数组中搜索文本?
- python - Python 脚本有效。当我在创建 exe 后尝试运行它时。它给了我“找不到路径”错误并传递了转义字符
- python - 如何移动 numpy 数组的列,以便前两个列到最后一个,最后两个到第一个?
- java - 我对课堂上的吸气剂和回报感到困惑?
- ruby-on-rails - 处理红宝石发送零
- bash - Bash 别名不保存超过一个会话?
- r - 每个人的子集重复项
- java - jframe中出现的“平方”字符