Java 如何修复SSLProtocolException:握手警报:在不禁用SNI的情况下无法识别\u名称
我制作了一个爬虫应用程序,由于出现错误“握手警报:无法识别的_名称”,一些网站无法连接 我找到的大多数解决方案都是通过禁用SNI扩展(jsse.enableSNIExtension=false)实现的。但这会给需要启用SNI的域带来问题 如何仅对某些域禁用它 为了进行爬网,我使用了Jsoup,因为我也使用了代理,所以我在启动时添加了这段代码Java 如何修复SSLProtocolException:握手警报:在不禁用SNI的情况下无法识别\u名称,java,ssl,java-8,jsoup,sni,Java,Ssl,Java 8,Jsoup,Sni,我制作了一个爬虫应用程序,由于出现错误“握手警报:无法识别的_名称”,一些网站无法连接 我找到的大多数解决方案都是通过禁用SNI扩展(jsse.enableSNIExtension=false)实现的。但这会给需要启用SNI的域带来问题 如何仅对某些域禁用它 为了进行爬网,我使用了Jsoup,因为我也使用了代理,所以我在启动时添加了这段代码 private static void disableSslVerification() { TrustManager[] trustAllCe
private static void disableSslVerification() {
TrustManager[] trustAllCertificates = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null; // Not relevant.
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
}
};
HostnameVerifier trustAllHostnames = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // Just allow them all.
}
};
try {
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
// System.setProperty("jsse.enableSNIExtension", "false");
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
}
catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
正如您所看到的,扩展被注释了。我希望能举个例子
我试图访问的url是下一个
https://www.ocinerioshopping.es/
我通过扩展SSLSocketConnection并在调用createSocket时发送null而不是主机名,成功地解决了这个问题。这样java就禁用了SNI。然后我将新类的一个实例传递给Jsoup,我知道SNI将失败
import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class CustomSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory defaultFactory;
public CustomSSLSocketFactory() throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init((KeyManager[])null, trustAllCerts, new SecureRandom());
defaultFactory = sslContext.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException var3) {
throw new IOException("Can't create unsecure trust manager");
}
}
@Override
public String[] getDefaultCipherSuites() {
return defaultFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return defaultFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
//magic happens here, we send null as hostname
return defaultFactory.createSocket(socket, null, i, b);
}
@Override
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i);
}
@Override
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i,inetAddress,i1);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return defaultFactory.createSocket(inetAddress, i);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
return defaultFactory.createSocket(inetAddress,i, inetAddress1, i1);
}
}
Jsoup初始化
Connection conn = Jsoup.connect(url);
conn.sslSocketFactory(new CustomSSLSocketFactory());
请参阅中描述的回退策略,不清楚的是我是否必须为每个请求执行回退策略,还是仅执行一次。还有,如果第二次没有主机名,这意味着什么?我必须解析域并获得ip吗?我的读数是1)对于每个失败的请求,2)是。另外,以他提供的提交链接为例,仅仅提出一个请求需要做大量的工作,我还必须找出如何将它与Jsoup集成。我试试看,谢谢。阅读链接答案的第一段。甲骨文的工程师们认为他们所做的是正确的。谢谢,很好的解决方案!也使用了
HttpsURLConnection
。