【问题标题】:Inconsistent SSLv3 handshake failure on AndroidAndroid 上不一致的 SSLv3 握手失败
【发布时间】:2016-04-08 11:09:55
【问题描述】:

我正在开发一个处理食品订单的应用程序,我们通过HttpsURLConnection 将请求发送到已通过 ssl 认证的 php 函数。我遇到的问题是它有时会拒绝握手,而不是其他人。我想知道是否有人可以向我解释为什么它会拒绝一次而不是另一次。

javax.net.ssl.SSLProtocolException:SSL 握手中止: ssl=0x56cbe008: SSL 库失败,通常是协议错误 错误:14077410:SSL 例程:SSL23_GET_SERVER_HELLO:sslv3 警报握手失败(外部/openssl/ssl/s23_clnt.c:744 0x52eb6d74:0x00000000) javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL 握手中止: ssl=0x56cbe008: SSL 库失败,通常是协议错误 错误:14077410:SSL 例程:SSL23_GET_SERVER_HELLO:sslv3 警报握手失败(外部/openssl/ssl/s23_clnt.c:744 0x52eb6d74:0x00000000)

url = new URL(request.endpointUri);

Log.d(LOG_TAG, "Opening connection to " + request.endpointUri);
conn = (HttpsURLConnection)url.openConnection();

//setup the connection
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("charset", "UTF-8");
conn.setDoInput(true);
conn.setDoOutput(true);

//setup the parameters
Uri.Builder params = new Uri.Builder();
String paramString;

params.appendQueryParameter("cctoken", request.token.getId());
params.appendQueryParameter("amt", Integer.toString(request.order.amount));
params.appendQueryParameter("email", request.order.customerEmail);
params.appendQueryParameter("order", request.order.details);

paramString = params.build().getEncodedQuery();
conn.setFixedLengthStreamingMode(paramString.getBytes("UTF-8").length);

Log.d(LOG_TAG, "Compiled query into: " + paramString);

//write the POST request params
OutputStream os = conn.getOutputStream();
BufferedWriter streamWriter = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
streamWriter.write(paramString);
streamWriter.flush();
streamWriter.close();
os.close();

//read the response
int responseCode = conn.getResponseCode();
InputStream is;

失败的行是它尝试收集输出的时候。

OutputStream os = conn.getOutputStream();

【问题讨论】:

    标签: java android ssl https


    【解决方案1】:

    相关问题:客户端和服务器不支持通用加密协议

    如果错误消息显示如下内容:

    error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x8d92d990:0x00000000)
    

    (注意在 'GET_SERVER_HELLO:' 之后写的是 'tlsv1' 而不是 'sslv3')这是一个微弱的线索,表明问题可能出在需要加密。如果客户端较旧,可能只支持 sslv2 或 sslv3。最新的服务器可能支持 TLS1.2,但不支持较旧的(可能已弃用的 ssl 版本。相反的情况也可能如此,服务器仅支持旧版本,客户端仅支持新版本。

    我在一个旧的 Android Jelly Bean 客户端遇到了这个问题,默认情况下,HttpsUrlConnection 不支持 TLS1.2。通过创建 TLSSocketFactory 和 X509TrustManager,并调用 setSSLSocketFactory(),我可以让旧版本的 Android 使用 TLS1.2,这让服务器很满意。 Navneet Krishna 很好地描述了如何做到这一点:https://medium.com/@krisnavneet/how-to-solve-sslhandshakeexception-in-android-ssl23-get-server-hello-tlsv1-alert-protocol-13b457c724ef

    【讨论】:

      【解决方案2】:

      此问题可能是由于您向其发送请求的服务器的自签名证书造成的。你必须做这样的事情: `// 从 InputStream 加载 CA //(可能来自资源或 ByteArrayInputStream 或 ...)

      CertificateFactory cf = CertificateFactory.getInstance("X.509");
      // From https://www.washington.edu/itconnect/security/ca/load-der.crt
      
      InputStream caInput = new BufferedInputStream(new FileInputStream("load-   der.crt"));
      Certificate ca;
      try {
      ca = cf.generateCertificate(caInput);
      System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
      } finally {
      caInput.close();
      }
      

      // 创建一个包含我们信任的 CA 的 KeyStore

      String keyStoreType = KeyStore.getDefaultType();
      KeyStore keyStore = KeyStore.getInstance(keyStoreType);
      keyStore.load(null, null);
      keyStore.setCertificateEntry("ca", ca);
      

      // 创建一个信任我们 KeyStore 中的 CA 的 TrustManager

      String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
      tmf.init(keyStore);
      

      // 创建一个使用我们的 TrustManager 的 SSLContext

      SSLContext context = SSLContext.getInstance("TLS");
      context.init(null, tmf.getTrustManagers(), null);
      

      //告诉 URLConnection 使用我们 SSLContext 中的 SocketFactory

      URL url = new URL("https://certs.cac.washington.edu/CAtest/");
      HttpsURLConnection urlConnection =
      (HttpsURLConnection)url.openConnection();
      urlConnection.setSSLSocketFactory(context.getSocketFactory());
      InputStream in = urlConnection.getInputStream();
      copyInputStreamToOutputStream(in, System.out);`
      

      Found it here

      【讨论】:

        【解决方案3】:

        有时只会发生的 SSL 握手错误通常与服务器端问题有关,因此您的代码在这里没有多大帮助。服务器端的可能原因是多台具有不同配置的服务器(有些工作,有些不工作),可能由负载过多引起的超时,服务器端崩溃。可能还涉及一些不稳定的中间件(防火墙),或者如果连接从一开始就不可靠,它也会影响 SSL 握手。

        因此,不要过多地查看您的代码,而要查看服务器和网络。如果有疑问,请尝试另一个客户端,如果这个客户端表现出更稳定的行为,请查看连接和 SSL 握手(即数据包捕获)的差异。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-10
          • 1970-01-01
          • 1970-01-01
          • 2016-07-03
          相关资源
          最近更新 更多