为了账号安全,请及时绑定邮箱和手机立即绑定

如何在不禁用 SNI 的情况下修复 SSLProtocolException:握手警报:

如何在不禁用 SNI 的情况下修复 SSLProtocolException:握手警报:

芜湖不芜 2023-02-23 16:14:32
我制作了一个爬虫应用程序,由于错误“握手警报:unrecognized_name”,某些网站无法连接。我发现的大多数解决方案是通过禁用 SNI 扩展 (jsse.enableSNIExtension=false)。但这会给需要启用 SNI 的域带来问题。我怎样才能只对某些域禁用它?为了进行爬行,我使用了 Jsoup,并且因为我也在使用代理,所以我在启动时添加了这段代码。  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);    }}如您所见,SNIextension 已被注释。我会很感激一个例子。我要访问的网址是下一个。https://www.ocinerioshopping.es/
查看完整描述

1 回答

?
慕的地10843

TA贡献1785条经验 获得超8个赞

我设法通过扩展 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());


查看完整回答
反对 回复 2023-02-23
  • 1 回答
  • 0 关注
  • 77 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信