【问题标题】:javax.net.ssl.SSLException: SSL handshake aborted on android old devicesjavax.net.ssl.SSLException: SSL 握手在 android 旧设备上中止
【发布时间】:2017-07-17 01:35:24
【问题描述】:

我有适用于大多数设备的 Android 应用程序 最近一些黑客试图对我们的服务器进行 DDOS 攻击,迫使我们添加一些安全性和一些防火墙

不是某些设备无法正常工作并给我以下异常

javax.net.ssl.SSLException: SSL handshake aborted: ssl=0x63eb8240: I/O error during system call, Connection reset by peer 

谁能告诉我现在是什么问题,我该如何解决?

编辑

这是我的执行方法的代码

public static BaseResponse execute(Context context, BaseRequest request) {

    mStartTime = System.nanoTime();

    BaseResponse response = new BaseResponse();
    DataOutputStream outputStream;
    try {
        URL url = new URL(request.getURL());
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setConnectTimeout(TIMEOUT_DURATION);
        urlConnection.setReadTimeout(TIMEOUT_DURATION);
        urlConnection.setRequestMethod(request.getRequestType().getValue());
        urlConnection.addRequestProperty("Accept", "application/json");
        urlConnection.addRequestProperty("Content-Type","application/json");
        urlConnection.setRequestProperty("Accept-Charset", CHARACTER_SET);
        urlConnection.addRequestProperty("Device-Id", PhoneUtils.getDeviceId(context));
        urlConnection.addRequestProperty("Version-Number", PhoneUtils.getAppVersion(context));


        TLSSocketFactory socketFactory = new TLSSocketFactory();
        urlConnection.setSSLSocketFactory(socketFactory);

        switch (request.getRequestType()) {
            case POST:
            case PUT:
                urlConnection.setDoOutput(true);
                if (request.getStringEntity() != null) {
                    outputStream = new DataOutputStream(urlConnection.getOutputStream());
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, CHARACTER_SET));
                    writer.write(request.getStringParam());
                    writer.close();
                    outputStream.flush();
                    outputStream.close();
                }

                break;
            case GET:
                urlConnection.setDoOutput(false);
                break;
        }

        urlConnection.connect();

        try {
            if (urlConnection.getResponseCode() == STATUS_OK) {
                InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuilder result = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }

                inputStream.close();
                response.setResponse(convertStringToJSONObject(result.toString()));
            } else {
                response.setResponse(null);
            }
        } catch (Exception ex) {
            response.setAppError(AppError.DATA_ERROR);
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
        response.setAppError(AppError.PARSING_ERROR);
    } catch (IOException e) {
        e.printStackTrace();
        response.setAppError(AppError.DATA_ERROR);
    } catch (Exception e) {
        e.printStackTrace();
        response.setAppError(AppError.DATA_ERROR);
    }

    return response;
}

【问题讨论】:

标签: android


【解决方案1】:

在进行任何网络调用之前在您的代码中使用它

/**
 * Initialize SSL
 * @param mContext
 */
public static void initializeSSLContext(Context mContext){
    try {
        SSLContext.getInstance("TLSv1.2");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    try {
        ProviderInstaller.installIfNeeded(mContext.getApplicationContext());
    } catch (GooglePlayServicesRepairableException e) {
        e.printStackTrace();
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }
}

我遇到了同样的问题,这段代码解决了我的问题。仅供参考:我正在使用改造库进行网络调用

您需要在build.gradle中包含以下行

implementation 'com.google.android.gms:play-services-safetynet:17.0.0

感谢@Houman 提供上述意见

【讨论】:

  • @Arshad 你能解释一下为什么这可以解决问题以及导致问题的原因吗?
  • 您需要将 implementation 'com.google.android.gms:play-services-safetynet:17.0.0' 添加到 build.gradle 以使 ProviderInstaller 正常工作。
【解决方案2】:

不同的 Android API 级别对 SSL/TLS 协议版本的支持不同,详情请参阅 Android 文档 - https://developer.android.com/reference/javax/net/ssl/SSLSocket.html

要启用 TLS 1.1 和 1.2,您需要创建自定义 SSLSocketFactory - https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        internalSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return internalSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return internalSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

然后在你的连接中使用它

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
TLSSocketFactory socketFactory = new TLSSocketFactory();
conn.setSSLSocketFactory(socketFactory);
conn.connect();

【讨论】:

  • HttpURLConnection 中没有名为 setSSLSocketFactory 的方法,你的目标安卓版本是什么?
  • 您可以将 HttpsURLConnection 用于 URL.openConnection 用于 https url,即 - HttpsURLConnection con = (HttpsURLConnection) new URL("google.com/").openConnection()
  • 我已经使用了你添加到答案中的类并在我的执行方法中使用它,但仍然有同样的问题,请检查我的编辑
  • 你可以试试其他版本的 TLSSocketFactory (SSLSocketFactoryCompat) - gitlab.com/bitfireAT/davdroid/blob/…
猜你喜欢
  • 2021-10-19
  • 2016-04-02
  • 1970-01-01
  • 2019-01-14
  • 2017-06-20
  • 2016-06-20
  • 1970-01-01
  • 2017-02-02
  • 2016-08-08
相关资源
最近更新 更多