Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: Bắt tay SSL bị hủy bỏ: Lỗi trong thư viện SSL, thường là lỗi giao thức


102

Tôi đang cố chạy đoạn mã sau trong android

URLConnection l_connection = null;
        // Create connection
        uzip=new UnZipData(mContext);
        l_url = new URL(serverurl);

        if ("https".equals(l_url.getProtocol())) {
            System.out.println("<<<<<<<<<<<<< Before TLS >>>>>>>>>>>>");
            sslcontext = SSLContext.getInstance("TLS");
            System.out.println("<<<<<<<<<<<<< After TLS >>>>>>>>>>>>");
            sslcontext.init(null,
                    new TrustManager[] { new CustomTrustManager()},
                    new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultHostnameVerifier(new CustomHostnameVerifier());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext
                    .getSocketFactory());

            l_connection = (HttpsURLConnection) l_url.openConnection();
            ((HttpsURLConnection) l_connection).setRequestMethod("POST");
        } else {
            l_connection = (HttpURLConnection) l_url.openConnection();
            ((HttpURLConnection) l_connection).setRequestMethod("POST");
        }
        /*System.setProperty("http.agent", "Android_Phone");*/


        l_connection.setConnectTimeout(10000);
        l_connection.setRequestProperty("Content-Language", "en-US");
        l_connection.setUseCaches(false);
        l_connection.setDoInput(true);
        l_connection.setDoOutput(true);
        System.out.println("<<<<<<<<<<<<< Before Connection >>>>>>>>>>>>");
        l_connection.connect();

Trên l_connection.connect(), nó đang cung cấp SSLhandshakeException này. Đôi khi nó hoạt động, nhưng hầu hết thời gian nó cho ngoại lệ. Nó chỉ xảy ra trên trình giả lập Android 4.0. Tôi đã thử nghiệm nó trên Android 4.4 và 5.0, nó hoạt động tốt. Điều gì có thể là nguyên nhân của việc này ? Xin vui lòng giúp đỡ

STACKTRACE

    04-28 15:51:13.143: W/System.err(2915): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.143: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.143: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:460)
04-28 15:51:13.143: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:257)
04-28 15:51:13.143: W/System.err(2915):     at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:210)
04-28 15:51:13.143: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:477)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:441)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:164)
04-28 15:51:13.153: W/System.err(2915):     at com.ofss.fcdb.mobile.android.rms.helpers.NetworkConnector.getConnection(NetworkConnector.java:170)
04-28 15:51:13.153: W/System.err(2915):     at com.ofss.fcdb.mobile.android.rms.util.InitiateRMS$2.run(InitiateRMS.java:221)
04-28 15:51:13.153: W/System.err(2915):     at java.lang.Thread.run(Thread.java:856)
04-28 15:51:13.153: W/System.err(2915): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.153: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.153: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
04-28 15:51:13.153: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:410)
04-28 15:51:13.153: W/System.err(2915):     ... 11 more
04-28 16:42:44.139: W/ResourceType(3140): No package identifier when getting value for resource number 0x00000000

bạn đã kiểm tra ứng dụng của mình trên thiết bị thực chưa?
Paresh Mayani

Nó đang đưa ra những gì ngoại lệ? Dấu vết ngăn xếp?
Marquis of Lorne

@PareshMayani Có, ngay cả trên thiết bị thực có Android 4.0, nó vẫn hiển thị ngoại lệ.
Bhavit S. Sengar

@EJP Tôi đã cập nhật câu hỏi, stacktrace được thêm vào.
Bhavit S. Sengar

Đây là câu hỏi duy nhất được gắn thẻ Jellybean. Ý của bạn là android-4.2-jelly-bean ?
Daniel Daranas

Câu trả lời:


120

Tôi đã tìm ra giải pháp cho nó bằng cách phân tích các gói dữ liệu bằng cách sử dụng wirehark. Những gì tôi phát hiện ra là trong khi tạo kết nối an toàn, android đã quay trở lại SSLv3 từ TLSv1 . Đó là một lỗi trong các phiên bản Android <4.4 và có thể khắc phục được bằng cách xóa giao thức SSLv3 khỏi danh sách Giao thức đã bật. Tôi đã tạo một lớp socketFactory tùy chỉnh có tên NoSSLv3SocketFactory.java. Sử dụng điều này để tạo ra một ổ cắm.

/*Copyright 2015 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;


public class NoSSLv3SocketFactory extends SSLSocketFactory{
    private final SSLSocketFactory delegate;

public NoSSLv3SocketFactory() {
    this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
}

public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
    this.delegate = delegate;
}

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

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

private Socket makeSocketSafe(Socket socket) {
    if (socket instanceof SSLSocket) {
        socket = new NoSSLv3SSLSocket((SSLSocket) socket);
    }
    return socket;
}

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

@Override
public Socket createSocket(String host, int port) throws IOException {
    return makeSocketSafe(delegate.createSocket(host, port));
}

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

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

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

private class NoSSLv3SSLSocket extends DelegateSSLSocket {

    private NoSSLv3SSLSocket(SSLSocket delegate) {
        super(delegate);

    }

    @Override
    public void setEnabledProtocols(String[] protocols) {
        if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {

            List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
            if (enabledProtocols.size() > 1) {
                enabledProtocols.remove("SSLv3");
                System.out.println("Removed SSLv3 from enabled protocols");
            } else {
                System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
            }
            protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
        }

        super.setEnabledProtocols(protocols);
    }
}

public class DelegateSSLSocket extends SSLSocket {

    protected final SSLSocket delegate;

    DelegateSSLSocket(SSLSocket delegate) {
        this.delegate = delegate;
    }

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

    @Override
    public String[] getEnabledCipherSuites() {
        return delegate.getEnabledCipherSuites();
    }

    @Override
    public void setEnabledCipherSuites(String[] suites) {
        delegate.setEnabledCipherSuites(suites);
    }

    @Override
    public String[] getSupportedProtocols() {
        return delegate.getSupportedProtocols();
    }

    @Override
    public String[] getEnabledProtocols() {
        return delegate.getEnabledProtocols();
    }

    @Override
    public void setEnabledProtocols(String[] protocols) {
        delegate.setEnabledProtocols(protocols);
    }

    @Override
    public SSLSession getSession() {
        return delegate.getSession();
    }

    @Override
    public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
        delegate.addHandshakeCompletedListener(listener);
    }

    @Override
    public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
        delegate.removeHandshakeCompletedListener(listener);
    }

    @Override
    public void startHandshake() throws IOException {
        delegate.startHandshake();
    }

    @Override
    public void setUseClientMode(boolean mode) {
        delegate.setUseClientMode(mode);
    }

    @Override
    public boolean getUseClientMode() {
        return delegate.getUseClientMode();
    }

    @Override
    public void setNeedClientAuth(boolean need) {
        delegate.setNeedClientAuth(need);
    }

    @Override
    public void setWantClientAuth(boolean want) {
        delegate.setWantClientAuth(want);
    }

    @Override
    public boolean getNeedClientAuth() {
        return delegate.getNeedClientAuth();
    }

    @Override
    public boolean getWantClientAuth() {
        return delegate.getWantClientAuth();
    }

    @Override
    public void setEnableSessionCreation(boolean flag) {
        delegate.setEnableSessionCreation(flag);
    }

    @Override
    public boolean getEnableSessionCreation() {
        return delegate.getEnableSessionCreation();
    }

    @Override
    public void bind(SocketAddress localAddr) throws IOException {
        delegate.bind(localAddr);
    }

    @Override
    public synchronized void close() throws IOException {
        delegate.close();
    }

    @Override
    public void connect(SocketAddress remoteAddr) throws IOException {
        delegate.connect(remoteAddr);
    }

    @Override
    public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
        delegate.connect(remoteAddr, timeout);
    }

    @Override
    public SocketChannel getChannel() {
        return delegate.getChannel();
    }

    @Override
    public InetAddress getInetAddress() {
        return delegate.getInetAddress();
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return delegate.getInputStream();
    }

    @Override
    public boolean getKeepAlive() throws SocketException {
        return delegate.getKeepAlive();
    }

    @Override
    public InetAddress getLocalAddress() {
        return delegate.getLocalAddress();
    }

    @Override
    public int getLocalPort() {
        return delegate.getLocalPort();
    }

    @Override
    public SocketAddress getLocalSocketAddress() {
        return delegate.getLocalSocketAddress();
    }

    @Override
    public boolean getOOBInline() throws SocketException {
        return delegate.getOOBInline();
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        return delegate.getOutputStream();
    }

    @Override
    public int getPort() {
        return delegate.getPort();
    }

    @Override
    public synchronized int getReceiveBufferSize() throws SocketException {
        return delegate.getReceiveBufferSize();
    }

    @Override
    public SocketAddress getRemoteSocketAddress() {
        return delegate.getRemoteSocketAddress();
    }

    @Override
    public boolean getReuseAddress() throws SocketException {
        return delegate.getReuseAddress();
    }

    @Override
    public synchronized int getSendBufferSize() throws SocketException {
        return delegate.getSendBufferSize();
    }

    @Override
    public int getSoLinger() throws SocketException {
        return delegate.getSoLinger();
    }

    @Override
    public synchronized int getSoTimeout() throws SocketException {
        return delegate.getSoTimeout();
    }

    @Override
    public boolean getTcpNoDelay() throws SocketException {
        return delegate.getTcpNoDelay();
    }

    @Override
    public int getTrafficClass() throws SocketException {
        return delegate.getTrafficClass();
    }

    @Override
    public boolean isBound() {
        return delegate.isBound();
    }

    @Override
    public boolean isClosed() {
        return delegate.isClosed();
    }

    @Override
    public boolean isConnected() {
        return delegate.isConnected();
    }

    @Override
    public boolean isInputShutdown() {
        return delegate.isInputShutdown();
    }

    @Override
    public boolean isOutputShutdown() {
        return delegate.isOutputShutdown();
    }

    @Override
    public void sendUrgentData(int value) throws IOException {
        delegate.sendUrgentData(value);
    }

    @Override
    public void setKeepAlive(boolean keepAlive) throws SocketException {
        delegate.setKeepAlive(keepAlive);
    }

    @Override
    public void setOOBInline(boolean oobinline) throws SocketException {
        delegate.setOOBInline(oobinline);
    }

    @Override
    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
        delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
    }

    @Override
    public synchronized void setReceiveBufferSize(int size) throws SocketException {
        delegate.setReceiveBufferSize(size);
    }

    @Override
    public void setReuseAddress(boolean reuse) throws SocketException {
        delegate.setReuseAddress(reuse);
    }

    @Override
    public synchronized void setSendBufferSize(int size) throws SocketException {
        delegate.setSendBufferSize(size);
    }

    @Override
    public void setSoLinger(boolean on, int timeout) throws SocketException {
        delegate.setSoLinger(on, timeout);
    }

    @Override
    public synchronized void setSoTimeout(int timeout) throws SocketException {
        delegate.setSoTimeout(timeout);
    }

    @Override
    public void setTcpNoDelay(boolean on) throws SocketException {
        delegate.setTcpNoDelay(on);
    }

    @Override
    public void setTrafficClass(int value) throws SocketException {
        delegate.setTrafficClass(value);
    }

    @Override
    public void shutdownInput() throws IOException {
        delegate.shutdownInput();
    }

    @Override
    public void shutdownOutput() throws IOException {
        delegate.shutdownOutput();
    }

    @Override
    public String toString() {
        return delegate.toString();
    }

    @Override
    public boolean equals(Object o) {
        return delegate.equals(o);
    }
}
}

Sử dụng lớp này như thế này trong khi kết nối:

SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
l_connection = (HttpsURLConnection) l_url.openConnection();
l_connection.connect();

CẬP NHẬT:

Bây giờ, giải pháp chính xác sẽ là cài đặt nhà cung cấp bảo mật mới hơn bằng Dịch vụ của Google Play :

    ProviderInstaller.installIfNeeded(getApplicationContext());

Điều này cấp cho ứng dụng của bạn một cách hiệu quả quyền truy cập vào phiên bản OpenSSL và Nhà cung cấp bảo mật Java mới hơn, bao gồm hỗ trợ cho TLSv1.2 trong SSLEngine. Sau khi nhà cung cấp mới được cài đặt, bạn có thể tạo SSLEngine hỗ trợ SSLv3, TLSv1, TLSv1.1 và TLSv1.2 theo cách thông thường:

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(null, null, null);
    SSLEngine engine = sslContext.createSSLEngine();

Hoặc bạn có thể hạn chế các giao thức được bật bằng cách sử dụng engine.setEnabledProtocols.

Đừng quên thêm phần phụ thuộc sau ( kiểm tra phiên bản mới nhất tại đây ):

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

Để biết thêm thông tin, hãy kiểm tra liên kết này .


25
Điều gì sẽ xảy ra nếu tôi gặp lỗi này trên thiết bị Lollipop?
IgorGanapolsky

2
Tôi nhận được điều này trên 5.0.1
Skynet

Cách tiếp cận này dường như không thành công khi kết nối với máy chủ ảo, vì nó vô hiệu hóa SNI một cách hiệu quả bằng cách không cung cấp phương thức SSLCertificateSocketFactory.setHostname (Socket, String). Tôi đã nhận được 403s trong đó sự cố openssl.exe và trình duyệt kết nối w / o. Hóa ra đó là SNI bị thiếu.
Jaroslav Záruba

2
làm thế nào một người có thể sử dụng điều này với bóng chuyền?
uniruddh

1
tôi đang nhận được lỗi này trong Android API 19 javax.net.ssl.SSLProtocolException: Đọc lỗi: ssl = 0xb83d7120: Thất bại trong thư viện SSL, thường là một lỗi giao thức
Rukmal Dias

117

Tình huống

Tôi nhận được ngoại lệ SSLHandshake trên các thiết bị chạy phiên bản Android cũ hơn Android 5.0. Trong trường hợp sử dụng của mình, tôi cũng muốn tạo TrustManager để tin cậy chứng chỉ khách hàng của mình.

Tôi đã triển khai NoSSLv3SocketFactoryNoSSLv3Factory để xóa SSLv3 khỏi danh sách các giao thức được hỗ trợ của khách hàng của tôi nhưng tôi không thể làm cho cả hai giải pháp này hoạt động.

Một số điều tôi học được:

  • Trên các thiết bị cũ hơn Android 5.0, giao thức TLSv1.1 và TLSv1.2 không được bật theo mặc định.
  • Giao thức SSLv3 không bị tắt theo mặc định trên các thiết bị cũ hơn Android 5.0.
  • SSLv3 không phải là một giao thức an toàn và do đó chúng tôi mong muốn xóa nó khỏi danh sách các giao thức được hỗ trợ của khách hàng của chúng tôi trước khi kết nối được thực hiện.

Điều gì đã làm việc cho tôi

Cho phép bảo mật của Android Providercập nhật khi khởi động ứng dụng của bạn.

Nhà cung cấp mặc định trước 5.0+ không tắt SSLv3. Miễn là bạn có quyền truy cập vào các dịch vụ của Google Play, việc vá Nhà cung cấp bảo mật của Android từ ứng dụng của bạn là tương đối đơn giản.

private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
        // Thrown when Google Play Services is not installed, up-to-date, or enabled
        // Show dialog to allow users to install, update, or otherwise enable Google Play services.
        GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

Nếu bây giờ bạn tạo OkHttpClient hoặc HttpURLConnection TLSv1.1 và TLSv1.2 sẽ có sẵn dưới dạng giao thức và SSLv3 sẽ bị xóa. Nếu máy khách / kết nối (hoặc cụ thể hơn là SSLContext) đã được khởi tạo trước khi gọi ProviderInstaller.installIfNeeded(...)thì nó sẽ cần được tạo lại.

Đừng quên thêm phần phụ thuộc sau ( phiên bản mới nhất được tìm thấy tại đây ):

compile 'com.google.android.gms:play-services-auth:16.0.1'

Nguồn:

Qua một bên

Tôi không cần phải đặt rõ ràng các thuật toán mật mã mà khách hàng của tôi nên sử dụng nhưng tôi đã tìm thấy một bài đăng SO đề xuất những thuật toán được coi là an toàn nhất tại thời điểm viết bài: Bộ mật mã nào để kích hoạt SSL Socket?


1
Tôi không biết bất kỳ thống kê nào đã xuất bản về số lượng thiết bị chạy Dịch vụ của Google Play. Con số mới nhất mà tôi có thể tìm thấy là cuộc nói chuyện IO 2014 của Sundar Pichai, nơi ông nói rằng 93% thiết bị Android có phiên bản mới nhất của Dịch vụ Play. Liên quan đến một phương pháp thủ công, tôi đã đến giải pháp này khi tất cả các phương pháp thủ công không hoạt động với tôi. Nếu bảo mật mạng không quan trọng đối với người dùng của bạn, bạn luôn có thể quay lại HTTP nếu người dùng từ chối cài đặt Dịch vụ Play. Đối với ứng dụng của riêng mình, chúng tôi đã cân nhắc sự đánh đổi giữa khả năng tương thích và bảo mật. Chúng tôi thực thi cập nhật Dịch vụ Play.
Maurice Gavin

3
Hỗ trợ Dịch vụ của Google Play ở Trung Quốc rất hạn chế. Có thể tốt để biết tùy thuộc vào đối tượng mục tiêu của bạn. Nhưng tốt, nếu bạn phân phối qua Google Play, đối tượng này đã bị bỏ lỡ.
jayeffkay

3
Vui lòng thêm phần phụ thuộc này để giải pháp hoạt động. biên dịch 'com.google.android.gms: play-services-auth: 10.2.0',
Pradeep Chakravarti Gudipati

3
Thêm ProviderInstaller.installIfNeeded (this); phần vào onCreate () của Ứng dụng đã làm việc cho tôi! Cảm ơn :-)
Kelevandos

1
Chắc chắn là câu trả lời hữu ích nhất ở đây. Cảm ơn vì một sự giúp đỡ vô giá.
Burak Karakuş

50

Ngoài ra, bạn nên biết rằng bạn có thể buộc TLS v1.2 cho các thiết bị Android 4.0 không được bật theo mặc định:

Đặt mã này vào onCreate () của tệp Ứng dụng của bạn :

try {
        ProviderInstaller.installIfNeeded(getApplicationContext());
        SSLContext sslContext;
        sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(null, null, null);
        sslContext.createSSLEngine();
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
            | NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
    }

7
Đã làm việc cho tôi với rxJava OkHttpClient.Builder, cảm ơn rất nhiều.
Gweltaz Niquel

2
Hoạt động trên Android 7.0.
CoolMind

1
cảm ơn @mayur gangurde, đây là công việc của tôi sau khi thêm dịch vụ chơi auth gradle, thực hiện 'com.google.android.gms: play-services-auth: 16.0.1'
Basant

Hoạt động hoàn hảo. Cảm ơn bạn rất nhiều vì đã tiết kiệm cho tôi hàng giờ thử nghiệm và cố gắng.
Ninad Desai

Điều này rất thuận tiện. Cảm ơn rất nhiều!
Caspar Geerlings

15

Trước đây, tôi cũng đã giải quyết vấn đề này bằng cách SSLFactorytriển khai tùy chỉnh , nhưng theo tài liệu OkHttp , giải pháp dễ dàng hơn nhiều.

Giải pháp cuối cùng của tôi với các TLSmật mã cần thiết cho thiết bị 4.2+ trông giống như sau:

public UsersApi provideUsersApi() {

    private ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
        .supportsTlsExtensions(true)
        .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
        .cipherSuites(
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
        .build();

    OkHttpClient client = new OkHttpClient.Builder()
            .connectionSpecs(Collections.singletonList(spec))
            .build();

    return new Retrofit.Builder()
            .baseUrl(USERS_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
            .create(UsersApi.class);
}

Lưu ý rằng tập hợp các giao thức được hỗ trợ phụ thuộc vào cấu hình trên máy chủ của bạn.


Giải pháp của bạn có hỗ trợ API 14 không?
CoolMind

Không thể nói chắc chắn, chỉ thử nghiệm này trên 16 thiết bị API, hoạt động tốt.
Fragment

1
Fragment, một biệt danh dễ thương :) Tôi đồng ý, thậm chí không thể khởi động trình mô phỏng API 14, nhưng giải pháp của bạn hoạt động trên Android 7.0 (có vấn đề) và trên API 19.
CoolMind 28/02 '19

1
Cảm ơn, tôi đã thử nghiệm, nó hoạt động. Hôm nay lại khởi chạy trình giả lập API 19 và phải thêm giải pháp stackoverflow.com/a/51285550/2914140 .
CoolMind

12

Tôi tìm thấy giải pháp ở đây trong liên kết này .

Bạn chỉ cần đặt mã bên dưới trong lớp ứng dụng Android của mình. Và như vậy là đủ. Không cần thực hiện bất kỳ thay đổi nào trong cài đặt Trang bị thêm của bạn. Nó đã cứu một ngày của tôi.

public class MyApplication extends Application {
@Override
public void onCreate() {
    super.onCreate();
    try {
      // Google Play will install latest OpenSSL 
      ProviderInstaller.installIfNeeded(getApplicationContext());
      SSLContext sslContext;
      sslContext = SSLContext.getInstance("TLSv1.2");
      sslContext.init(null, null, null);
      sslContext.createSSLEngine();
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
        | NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
        }
    }
}

Hy vọng điều này sẽ được giúp đỡ. Cảm ơn bạn.


4

Điều này đã giải quyết nó cho tôi:

Tài liệu Android cho SSLSocket nói rằng TLS 1.1 và TLS 1.2 được hỗ trợ trong API bắt đầu Android cấp 16+ (Android 4.1, Jelly Bean). Tuy nhiên, nó được tắt theo mặc định nhưng bắt đầu với API cấp 20+ (Android 4.4 cho đồng hồ, Kitkat Watch và Android 5.0 cho điện thoại, Lollipop) chúng được bật. Nhưng rất khó để tìm thấy bất kỳ tài liệu nào về cách bật nó cho điện thoại chạy 4.1 chẳng hạn. Để bật TLS 1.1 và 1.2, bạn cần tạo SSLSocketFactory tùy chỉnh sẽ ủy quyền cho tất cả các cuộc gọi đến triển khai SSLSocketFactory mặc định. Ngoài ra, chúng ta phải ghi đè tất cả các phương thức createSocket và calletEnabledProtocols trên SSLSocket trả về để kích hoạt TLS 1.1 và TLS 1.2. Đối với một ví dụ triển khai, chỉ cần theo liên kết bên dưới.

android 4.1. bật tls1.1 và tls 1.2


2

Tôi cũng gặp sự cố báo cáo lỗi này. Mã của tôi ở dưới đây.

public static void getShop() throws Exception {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url("https://10.0.2.2:8010/getShopInfo/aaa")
                        .build();
                Response response = client.newCall(request).execute();
                Log.d("response", response.body().string());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

Tôi có Springboot làm chương trình phụ trợ và sử dụng Android OKHttp để nhận thông tin. Sai lầm nghiêm trọng mà tôi đã mắc phải là tôi sử dụng .url ( "https : //10.0.2.2: 8010 / getShopInfo / aaa") trong mã của Android. Nhưng chương trình phụ trợ của tôi không được phép yêu cầu https. Sau khi tôi sử dụng .url (" http : //10.0.2.2: 8010 / getShopInfo / aaa") , thì mã của tôi đã hoạt động tốt. Vì vậy, tôi muốn nói rằng sai lầm của tôi không phải là phiên bản của trình giả lập, mà là về giao thức yêu cầu. Tôi gặp một vấn đề khác sau khi thực hiện những gì tôi đã nói, nhưng đó là một vấn đề khác và tôi đính kèm phương pháp giải quyết vấn đề mới .
Chúc may mắn! GUY!


1

Nó chỉ có thể tái tạo khi tôi sử dụng proxy trên genymotion (<4,4).

Kiểm tra cài đặt proxy của bạn trong Cài đặt-> Không dây & Mạng-> WiFi -> (Nhấn và giữ WiredSSID) -> Sửa đổi mạng

Chọn hiển thị các tùy chọn nâng cao: đặt cài đặt Proxy thành KHÔNG.


1

Khi tôi gặp lỗi này, đó là do các giao thức (phiên bản TLS) và / hoặc bộ mật mã được máy chủ hỗ trợ không được bật trên (và thậm chí có thể không được hỗ trợ bởi) thiết bị. Đối với API 16-19, TLSv1.1 và TLSv1.2 được hỗ trợ nhưng không được bật theo mặc định. Sau khi bật chúng cho các phiên bản này, tôi vẫn gặp lỗi vì các phiên bản này không hỗ trợ bất kỳ mật mã nào trên phiên bản AWS CloudFront của chúng tôi.

Vì không thể thêm mật mã vào Android, chúng tôi đã phải chuyển phiên bản CloudFront của mình từ TLSv1.2_2018 sang TLSv1.1_2016 (vẫn hỗ trợ TLSv1.2; không yêu cầu), phiên bản này có bốn trong số các mật mã được hỗ trợ bởi các phiên bản Android trước đó, hai trong số đó vẫn được coi là mạnh.

Tại thời điểm đó, lỗi đã biến mất và các cuộc gọi được thực hiện (với TLSv1.2) vì có ít nhất một giao thức và ít nhất một mật mã mà thiết bị và máy chủ chia sẻ.

Tham khảo các bảng trên trang này để xem giao thức và mật mã nào được hỗ trợ và kích hoạt trên phiên bản Android nào.

Android có thực sự đang cố gắng sử dụng SSLv3 như được ngụ ý bởi phần "lỗi bắt tay cảnh báo sslv3" của thông báo lỗi không? Tôi nghi ngờ điều đó; Tôi nghi ngờ đây là một mạng nhện cũ trong thư viện SSL chưa được dọn sạch nhưng tôi không thể nói chắc chắn.

Để bật TLSv1.2 (và TLSv1.1), tôi đã có thể sử dụng một cách đơn giản SSLSocketFactoryhơn nhiều so với những cái đã thấy ở nơi khác (như NoSSLv3SocketFactory). Nó chỉ đơn giản đảm bảo rằng các giao thức được kích hoạt bao gồm tất cả các giao thức được hỗ trợ và các mật mã được kích hoạt bao gồm tất cả các mật mã được hỗ trợ (cái sau không cần thiết đối với tôi nhưng nó có thể dành cho những người khác) - xem configure()ở dưới cùng. Nếu bạn chỉ muốn kích hoạt các giao thức mới nhất, bạn có thể thay thế socket.supportedProtocolsbằng một cái gì đó như arrayOf("TLSv1.1", "TLSv1.2")(tương tự như vậy đối với mật mã):

class TLSSocketFactory : SSLSocketFactory() {

    private val socketFactory: SSLSocketFactory

    init {
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, null, null)
        socketFactory = sslContext.socketFactory
    }

    override fun getDefaultCipherSuites(): Array<String> {
        return socketFactory.defaultCipherSuites
    }

    override fun getSupportedCipherSuites(): Array<String> {
        return socketFactory.supportedCipherSuites
    }

    override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
        return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket)
    }

    override fun createSocket(host: String, port: Int): Socket {
        return configure(socketFactory.createSocket(host, port) as SSLSocket)
    }

    override fun createSocket(host: InetAddress, port: Int): Socket {
        return configure(socketFactory.createSocket(host, port) as SSLSocket)
    }

    override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
        return configure(socketFactory.createSocket(host, port, localHost, localPort) as SSLSocket)
    }

    override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
        return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket)
    }

    private fun configure(socket: SSLSocket): SSLSocket {
        socket.enabledProtocols = socket.supportedProtocols
        socket.enabledCipherSuites = socket.supportedCipherSuites
        return socket
    }
}

Làm thế nào để bạn sử dụng nó?
CoolMind

0

Tôi đã giải quyết vấn đề bằng cách này: NoSSLv3SocketFactory.java

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class NoSSLv3SocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory delegate;

    public NoSSLv3SocketFactory() {
        this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
    }

    public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

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

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

    private Socket makeSocketSafe(Socket socket) {
        if (socket instanceof SSLSocket) {
            socket = new NoSSLv3SSLSocket((SSLSocket) socket);
        }
        return socket;
    }

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

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port));
    }

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

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

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

    private class NoSSLv3SSLSocket extends DelegateSSLSocket {

        private NoSSLv3SSLSocket(SSLSocket delegate) {
            super(delegate);

        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            if (protocols != null && protocols.length == 1
                    && "SSLv3".equals(protocols[0])) {

                List<String> enabledProtocols = new ArrayList<String>(
                        Arrays.asList(delegate.getEnabledProtocols()));
                if (enabledProtocols.size() > 1) {
                    enabledProtocols.remove("SSLv3");
                    System.out.println("Removed SSLv3 from enabled protocols");
                } else {
                    System.out.println("SSL stuck with protocol available for "
                            + String.valueOf(enabledProtocols));
                }
                protocols = enabledProtocols
                        .toArray(new String[enabledProtocols.size()]);
            }

//          super.setEnabledProtocols(protocols);
            super.setEnabledProtocols(new String[]{"TLSv1.2"});
        }
    }

    public class DelegateSSLSocket extends SSLSocket {

        protected final SSLSocket delegate;

        DelegateSSLSocket(SSLSocket delegate) {
            this.delegate = delegate;
        }

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

        @Override
        public String[] getEnabledCipherSuites() {
            return delegate.getEnabledCipherSuites();
        }

        @Override
        public void setEnabledCipherSuites(String[] suites) {
            delegate.setEnabledCipherSuites(suites);
        }

        @Override
        public String[] getSupportedProtocols() {
            return delegate.getSupportedProtocols();
        }

        @Override
        public String[] getEnabledProtocols() {
            return delegate.getEnabledProtocols();
        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            delegate.setEnabledProtocols(protocols);
        }

        @Override
        public SSLSession getSession() {
            return delegate.getSession();
        }

        @Override
        public void addHandshakeCompletedListener(
                HandshakeCompletedListener listener) {
            delegate.addHandshakeCompletedListener(listener);
        }

        @Override
        public void removeHandshakeCompletedListener(
                HandshakeCompletedListener listener) {
            delegate.removeHandshakeCompletedListener(listener);
        }

        @Override
        public void startHandshake() throws IOException {
            delegate.startHandshake();
        }

        @Override
        public void setUseClientMode(boolean mode) {
            delegate.setUseClientMode(mode);
        }

        @Override
        public boolean getUseClientMode() {
            return delegate.getUseClientMode();
        }

        @Override
        public void setNeedClientAuth(boolean need) {
            delegate.setNeedClientAuth(need);
        }

        @Override
        public void setWantClientAuth(boolean want) {
            delegate.setWantClientAuth(want);
        }

        @Override
        public boolean getNeedClientAuth() {
            return delegate.getNeedClientAuth();
        }

        @Override
        public boolean getWantClientAuth() {
            return delegate.getWantClientAuth();
        }

        @Override
        public void setEnableSessionCreation(boolean flag) {
            delegate.setEnableSessionCreation(flag);
        }

        @Override
        public boolean getEnableSessionCreation() {
            return delegate.getEnableSessionCreation();
        }

        @Override
        public void bind(SocketAddress localAddr) throws IOException {
            delegate.bind(localAddr);
        }

        @Override
        public synchronized void close() throws IOException {
            delegate.close();
        }

        @Override
        public void connect(SocketAddress remoteAddr) throws IOException {
            delegate.connect(remoteAddr);
        }

        @Override
        public void connect(SocketAddress remoteAddr, int timeout)
                throws IOException {
            delegate.connect(remoteAddr, timeout);
        }

        @Override
        public SocketChannel getChannel() {
            return delegate.getChannel();
        }

        @Override
        public InetAddress getInetAddress() {
            return delegate.getInetAddress();
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return delegate.getInputStream();
        }

        @Override
        public boolean getKeepAlive() throws SocketException {
            return delegate.getKeepAlive();
        }

        @Override
        public InetAddress getLocalAddress() {
            return delegate.getLocalAddress();
        }

        @Override
        public int getLocalPort() {
            return delegate.getLocalPort();
        }

        @Override
        public SocketAddress getLocalSocketAddress() {
            return delegate.getLocalSocketAddress();
        }

        @Override
        public boolean getOOBInline() throws SocketException {
            return delegate.getOOBInline();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return delegate.getOutputStream();
        }

        @Override
        public int getPort() {
            return delegate.getPort();
        }

        @Override
        public synchronized int getReceiveBufferSize() throws SocketException {
            return delegate.getReceiveBufferSize();
        }

        @Override
        public SocketAddress getRemoteSocketAddress() {
            return delegate.getRemoteSocketAddress();
        }

        @Override
        public boolean getReuseAddress() throws SocketException {
            return delegate.getReuseAddress();
        }

        @Override
        public synchronized int getSendBufferSize() throws SocketException {
            return delegate.getSendBufferSize();
        }

        @Override
        public int getSoLinger() throws SocketException {
            return delegate.getSoLinger();
        }

        @Override
        public synchronized int getSoTimeout() throws SocketException {
            return delegate.getSoTimeout();
        }

        @Override
        public boolean getTcpNoDelay() throws SocketException {
            return delegate.getTcpNoDelay();
        }

        @Override
        public int getTrafficClass() throws SocketException {
            return delegate.getTrafficClass();
        }

        @Override
        public boolean isBound() {
            return delegate.isBound();
        }

        @Override
        public boolean isClosed() {
            return delegate.isClosed();
        }

        @Override
        public boolean isConnected() {
            return delegate.isConnected();
        }

        @Override
        public boolean isInputShutdown() {
            return delegate.isInputShutdown();
        }

        @Override
        public boolean isOutputShutdown() {
            return delegate.isOutputShutdown();
        }

        @Override
        public void sendUrgentData(int value) throws IOException {
            delegate.sendUrgentData(value);
        }

        @Override
        public void setKeepAlive(boolean keepAlive) throws SocketException {
            delegate.setKeepAlive(keepAlive);
        }

        @Override
        public void setOOBInline(boolean oobinline) throws SocketException {
            delegate.setOOBInline(oobinline);
        }

        @Override
        public void setPerformancePreferences(int connectionTime, int latency,
                int bandwidth) {
            delegate.setPerformancePreferences(connectionTime, latency,
                    bandwidth);
        }

        @Override
        public synchronized void setReceiveBufferSize(int size)
                throws SocketException {
            delegate.setReceiveBufferSize(size);
        }

        @Override
        public void setReuseAddress(boolean reuse) throws SocketException {
            delegate.setReuseAddress(reuse);
        }

        @Override
        public synchronized void setSendBufferSize(int size)
                throws SocketException {
            delegate.setSendBufferSize(size);
        }

        @Override
        public void setSoLinger(boolean on, int timeout) throws SocketException {
            delegate.setSoLinger(on, timeout);
        }

        @Override
        public synchronized void setSoTimeout(int timeout)
                throws SocketException {
            delegate.setSoTimeout(timeout);
        }

        @Override
        public void setTcpNoDelay(boolean on) throws SocketException {
            delegate.setTcpNoDelay(on);
        }

        @Override
        public void setTrafficClass(int value) throws SocketException {
            delegate.setTrafficClass(value);
        }

        @Override
        public void shutdownInput() throws IOException {
            delegate.shutdownInput();
        }

        @Override
        public void shutdownOutput() throws IOException {
            delegate.shutdownOutput();
        }

        @Override
        public String toString() {
            return delegate.toString();
        }

        @Override
        public boolean equals(Object o) {
            return delegate.equals(o);
        }
    }
}

Lớp chính :

URL url = new URL("https://www.example.com/test.png");
URLConnection l_connection = null;
SSLContext sslcontext = SSLContext.getInstance("TLSv1.2");
sslcontext.init(null, null, null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

0

Câu trả lời của tôi gần với các câu trả lời trên nhưng bạn cần phải viết lớp chính xác mà không thay đổi bất cứ điều gì.

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory delegate;

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

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

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

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

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

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

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

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

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
    return enableTLSOnSocket(delegate.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;
}

}

và sử dụng nó với HttpsURLConnection

HttpsURLConnection  conn = (HttpsURLConnection) url.openConnection();

int sdk = android.os.Build.VERSION.SDK_INT;
            if (sdk < Build.VERSION_CODES.LOLLIPOP) {
                if (url.toString().startsWith("https")) {
                    try {
                        TLSSocketFactory sc = new TLSSocketFactory();
                        conn.setSSLSocketFactory(sc);
                    } catch (Exception e) {
                        String sss = e.toString();
                    }
                }
            }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.