如何修复(SSLException)收到致命警报:Java中的protocol_version

时间:2015-10-01 23:46:19

标签: java ssl encryption https apache-httpclient-4.x

我试图对网站https://www.facebookbrand.com/执行get调用,并且这样做我收到错误(SSLException)收到致命警报:protocol_version。有问题的网站正在使用TLSv1.2,如果我设置我的ConnectionFactory专门支持这个协议只有它工作正常,但我需要它为每个网站工作,从我的理解硬编码到TLSv1.2会使它无法正常工作对于其他不使用TLSv1.2的https网站。我还尝试了一个协议列表(" TLSv1.2"," TLSv1.1"," TLSv1"," SSLv3",& #34; SSLv2Hello")但后来我收到错误无法识别的SSL消息,明文连接。我并不关心它的安全性我只需要能够连接到每个网站,并且我正在努力寻找最佳方法。下面我已经包含了我的代码。

这是我设置httpClient等的代码:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslBuilder.build(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
PlainConnectionSocketFactory pcsf = new PlainConnectionSocketFactory();
Registry socketFactoryRegistry = RegistryBuilder.create().register("https", sslsf).register("http", pcsf).build();
PoolingHttpClientConnectionManager multiConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
multiConnectionManager.setMaxTotal(100);
multiConnectionManager.setDefaultMaxPerRoute(10);
httpClientBuilder.setConnectionManager(multiConnectionManager);
this.httpClient = httpClientBuilder.disableContentCompression().setSSLSocketFactory(sslsf).build();

这里是通过httpClient获取请求和执行的代码:

HttpGet call = new HttpGet(url);
LinkPullerContentHandler handler = new LinkPullerContentHandler();
PageLinks pl = new PageLinks(url, 200, null);
HttpResponse getResponse;

try {
    call.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)");
    call.addHeader("Accept","text/html");
    call.setConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build());

    try {
        getResponse = httpClient.execute(call);
    } catch (SocketTimeoutException ste) {
        LOG.error(String.format("Socket timeout pulling URL %s; skipping",url));
        pl.setHttpStatusCode(408);
        return pl;
    } catch (ConnectTimeoutException cte) {
        LOG.warn(String.format("Connect timeout pulling URL %s; skipping", url));
        pl.setHttpStatusCode(408);
        return pl;
    } catch (UnknownHostException uhe) {
        LOG.warn("Unable to resolve host for URL {}; skipping", url);
        pl.setHttpStatusCode(404);
        return pl;
    } catch (Exception e) {
        LOG.error(String.format("Unable to load link %s: (%s) %s",
            url,e.getClass().getSimpleName(),e.getMessage()),e);
        pl.setHttpStatusCode(420);
        return pl;
    }

    int code = getResponse.getStatusLine().getStatusCode();

在尝试特别包含TLSv1.2协议时,我将SSLConnectionSocketFactory设置代码修改为:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslBuilder.build(),
                new String[] { "TLSv1.2" }, null,
                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

哪个适用于有问题的网站,但我觉得它会因为它被硬编码到TLSv1.2而在其他一些网站上失败。另外,这是我尝试包含其他协议时的样子:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslBuilder.build(),
                new String[] { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello"},
                null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

最终得到异常"无法识别的SSL消息,明文连接。"我也试图列出一个cipherSuites列表,看看这是否有帮助,但我还没有取得任何成功。

任何人都可以提供帮助,帮助我弄清楚如何在不牺牲能够获得其他网站的情况下完成这项工作。

提前致谢

1 个答案:

答案 0 :(得分:2)

请勿使用SSLv2Hello。

那个网站显然不支持v2格式你好;即使它将成功地在v3 +格式hello上协商TLSv1.2,如果我发送(使用openssl)v2格式支持升级到TLSv1.2(有线版本3.3),它会以明文形式响应HTML正文(甚至不是HTTP头)说“服务不可用”和“网站不可用”。这当然不是对v2协议或v3 +协议的有效响应。

如果您配置SSLv3到TLSv1.2的所有协议,而不是SSLv2Hello - 这是Java8的默认协议 - 您将能够与其他支持SSLv3的网站进行协商,假设没有其他问题,例如该网站使用无效的证书。 (除了任何实现草案TLSv1.3并且没有任何标准的网站。)如果还有任何服务器仍然存在,那么它只支持SSLv2,那么Java实际上无法与它进行通信; SSLv2Hello唯一的“好处”是JSSE抛出了一个关于“不支持SSLv2”的特定异常,而不是变化的,而且通常是模糊的通信错误,这些错误很难调试。