Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake ถูกยกเลิก: ความล้มเหลวในไลบรารี SSL โดยปกติจะเป็นข้อผิดพลาดของโปรโตคอล


102

ฉันพยายามเรียกใช้รหัสต่อไปนี้ใน 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();

บนl_connection.connect()มันกำลังให้ SSLhandshakeException นี้ บางครั้งก็ใช้งานได้ แต่ส่วนใหญ่จะให้ข้อยกเว้น มันเกิดขึ้นบนโปรแกรมจำลอง Android 4.0 เท่านั้น ฉันทดสอบบน Android 4.4 และ 5.0 มันใช้งานได้ดี อะไรคือสาเหตุของสิ่งนี้? กรุณาช่วย

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

คุณตรวจสอบแอปของคุณบนอุปกรณ์จริงหรือไม่
Paresh Mayani

มันให้ข้อยกเว้นอะไร? ติดตามกอง?
Marquis of Lorne

@PareshMayani ใช่แม้ในอุปกรณ์จริงที่มี Android 4.0 แต่ก็แสดงข้อยกเว้น
Bhavit S.Sengar

@EJP ฉันได้อัปเดตคำถามแล้วมีการเพิ่ม stacktrace
Bhavit S.Sengar

นี่เป็นคำถามเดียวที่ติดแท็ก jellybean คุณหมายถึงandroid-4.2-jelly-bean ?
Daniel Daranas

คำตอบ:


120

ฉันพบวิธีแก้ปัญหานี้โดยการวิเคราะห์แพ็กเก็ตข้อมูลโดยใช้ wirehark สิ่งที่ผมพบก็คือว่าในขณะที่การเชื่อมต่อที่ปลอดภัย, Android กำลังตกกลับไปSSLv3จากTLSv1 เป็นข้อบกพร่องใน Android เวอร์ชัน <4.4 และสามารถแก้ไขได้โดยการลบโปรโตคอล SSLv3 ออกจากรายการโปรโตคอลที่เปิดใช้งาน ฉันสร้างคลาส socketFactory ที่กำหนดเองชื่อ NoSSLv3SocketFactory.java ใช้สิ่งนี้เพื่อสร้างโรงงานซ็อกเก็ต

/*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);
    }
}
}

ใช้คลาสนี้ในลักษณะนี้ขณะเชื่อมต่อ:

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();

อัพเดท:

ตอนนี้วิธีแก้ไขที่ถูกต้องคือการติดตั้งผู้ให้บริการความปลอดภัยรุ่นใหม่โดยใช้บริการGoogle Play :

    ProviderInstaller.installIfNeeded(getApplicationContext());

สิ่งนี้ช่วยให้แอปของคุณสามารถเข้าถึง OpenSSL และ Java Security Provider เวอร์ชันใหม่กว่าได้อย่างมีประสิทธิภาพซึ่งรวมถึงการรองรับ TLSv1.2 ใน SSLEngine เมื่อติดตั้งผู้ให้บริการใหม่แล้วคุณสามารถสร้าง SSLEngine ซึ่งรองรับ SSLv3, TLSv1, TLSv1.1 และ TLSv1.2 ได้ตามปกติ:

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

หรือคุณสามารถ จำกัด โปรโตคอลที่เปิดใช้งานโดยใช้engine.setEnabledProtocols.

อย่าลืมเพิ่มการอ้างอิงต่อไปนี้ ( ตรวจสอบเวอร์ชันล่าสุดที่นี่ ):

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

สำหรับข้อมูลเพิ่มเติมโปรดดูที่ลิงค์นี้


25
จะเกิดอะไรขึ้นหากฉันได้รับข้อผิดพลาดนี้บนอุปกรณ์ Lollipop
IgorGanapolsky

2
ฉันได้รับสิ่งนี้ในวันที่ 5.0.1
Skynet

วิธีนี้ดูเหมือนจะล้มเหลวเมื่อเชื่อมต่อกับโฮสต์เสมือนเนื่องจากปิดใช้งาน SNI ได้อย่างมีประสิทธิภาพโดยไม่ระบุเมธอด SSLCertificateSocketFactory.setHostname (Socket, String) ฉันได้รับ 403 ที่ openssl.exe และเบราว์เซอร์เชื่อมต่อโดยไม่มีปัญหา ปรากฎว่าเป็น SNI ที่หายไป
Jaroslav Záruba

2
จะใช้กับวอลเลย์ได้อย่างไร?
uniruddh

1
ฉันได้รับข้อผิดพลาดนี้ใน Android API 19 javax.net.ssl.SSLProtocolException: อ่านข้อผิดพลาด: ssl = 0xb83d7120: ความล้มเหลวในไลบรารี SSL โดยปกติจะเป็นข้อผิดพลาดของโปรโตคอล
Rukmal Dias

117

สถานการณ์

ฉันได้รับข้อยกเว้น SSLHandshake ในอุปกรณ์ที่ใช้ Android เวอร์ชันก่อนหน้า Android 5.0 ในกรณีการใช้งานของฉันฉันยังต้องการสร้าง TrustManager เพื่อเชื่อถือใบรับรองไคลเอ็นต์ของฉัน

ฉันใช้NoSSLv3SocketFactoryและNoSSLv3Factoryเพื่อลบ SSLv3 ออกจากรายการโปรโตคอลที่รองรับของไคลเอ็นต์ แต่ฉันไม่สามารถใช้โซลูชันเหล่านี้ได้

บางสิ่งที่ฉันได้เรียนรู้:

  • บนอุปกรณ์ที่เก่ากว่า Android 5.0 TLSv1.1 และโปรโตคอล TLSv1.2 จะไม่เปิดใช้งานโดยค่าเริ่มต้น
  • โปรโตคอล SSLv3 จะไม่ถูกปิดใช้งานโดยค่าเริ่มต้นในอุปกรณ์ที่เก่ากว่า Android 5.0
  • SSLv3 ไม่ใช่โปรโตคอลที่ปลอดภัยดังนั้นจึงเป็นที่พึงปรารถนาที่จะลบออกจากรายการโปรโตคอลที่รองรับของไคลเอ็นต์ของเราก่อนที่จะทำการเชื่อมต่อ

อะไรที่เหมาะกับฉัน

อนุญาตให้Providerอัปเดตความปลอดภัยของ Android เมื่อเริ่มแอปของคุณ

ผู้ให้บริการเริ่มต้นก่อน 5.0+ ไม่ปิดใช้งาน SSLv3 หากคุณสามารถเข้าถึงบริการ Google Play ได้การแก้ไขผู้ให้บริการความปลอดภัยของ Android จากแอปของคุณนั้นค่อนข้างตรงไปตรงมา

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.");
    }
}

หากตอนนี้คุณสร้าง OkHttpClient หรือ HttpURLConnection TLSv1.1 และ TLSv1.2 ควรพร้อมใช้งานเป็นโปรโตคอลและควรลบ SSLv3 หากไคลเอนต์ / การเชื่อมต่อ (หรือมากกว่านั้นโดยเฉพาะอย่างยิ่ง SSLContext) ถูกเริ่มต้นก่อนที่จะโทรProviderInstaller.installIfNeeded(...)ก็จะต้องสร้างใหม่

อย่าลืมเพิ่มการอ้างอิงต่อไปนี้ ( พบเวอร์ชันล่าสุดที่นี่ ):

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

แหล่งที่มา:

นอกจากนี้

ฉันไม่จำเป็นต้องตั้งค่าอย่างชัดเจนว่าอัลกอริทึมการเข้ารหัสใดที่ไคลเอ็นต์ของฉันควรใช้ แต่ฉันพบโพสต์ SO ที่แนะนำผู้ที่ถือว่าปลอดภัยที่สุดในขณะที่เขียน: Cipher Suites ใดที่จะเปิดใช้งานสำหรับ SSL Socket


1
ฉันไม่ทราบสถิติที่เผยแพร่สำหรับจำนวนอุปกรณ์ที่ใช้บริการ Google Play ตัวเลขล่าสุดที่ฉันพบคือการพูดคุยเกี่ยวกับ IO 2014 ของ Sundar Pichai ซึ่งเขากล่าวว่า 93% ของอุปกรณ์ Android มี Play Services เวอร์ชันล่าสุด เกี่ยวกับวิธีการแบบแมนนวลฉันมาถึงโซลูชันนี้เมื่อวิธีการแบบแมนนวลทั้งหมดไม่สามารถใช้งานได้สำหรับฉัน หากความปลอดภัยของเครือข่ายไม่สำคัญสำหรับผู้ใช้ของคุณคุณสามารถกลับไปใช้ HTTP ได้ตลอดเวลาหากผู้ใช้ปฏิเสธที่จะติดตั้ง Play Services สำหรับแอปของเราเองเราถือว่าเป็นการแลกเปลี่ยนระหว่างความเข้ากันได้และความปลอดภัย เราบังคับใช้การอัปเดตบริการ Play
Maurice Gavin

3
การสนับสนุนบริการ Google Play ในประเทศจีนมีข้อ จำกัด มาก สิ่งที่ควรทราบขึ้นอยู่กับกลุ่มเป้าหมายของคุณ แต่ถ้าคุณเผยแพร่ผ่าน Google Play ผู้ชมกลุ่มนี้ก็พลาดไปแล้ว
jayeffkay

3
โปรดเพิ่มการอ้างอิงนี้เพื่อให้โซลูชันใช้งานได้ รวบรวม 'com.google.android.gms: play-services-auth: 10.2.0',
Pradeep Chakravarti Gudipati

3
การเพิ่ม ProviderInstaller.installIfNeeded (this); ส่วนหนึ่งใน onCreate () ของแอปพลิเคชันทำงานให้ฉัน! ขอบคุณ :-)
Kelevandos

1
คำตอบที่มีประโยชน์ที่สุดที่นี่ ขอบคุณสำหรับความช่วยเหลืออันล้ำค่าเช่นนี้
Burak Karakuş

50

นอกจากนี้คุณควรทราบว่าคุณสามารถบังคับ TLS v1.2 สำหรับอุปกรณ์ Android 4.0 ที่ไม่ได้เปิดใช้งานโดยค่าเริ่มต้น:

ใส่รหัสนี้ใน onCreate () ของไฟล์ Application ของคุณ :

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
ทำงานให้ฉันด้วย rxJava OkHttpClient.Builder ขอบคุณมาก
Gweltaz Niquel

2
ทำงานบน Android 7.0
CoolMind

1
ขอบคุณ @mayur gangurde นี่เป็นงานของฉันหลังจากเพิ่มบริการเล่น auth gradle การใช้งาน 'com.google.android.gms: play-services-auth: 16.0.1'
Basant

ทำงานได้อย่างสมบูรณ์แบบ ขอบคุณมากที่ช่วยประหยัดเวลาในการทดสอบและลองใช้
Ninad Desai

นี้สะดวกมาก ขอบคุณมาก!
Caspar Geerlings

15

ก่อนหน้านี้ฉันได้แก้ไขปัญหานี้ด้วยSSLFactoryการใช้งานแบบกำหนดเองแต่ตามเอกสารของ OkHttpการแก้ปัญหานั้นง่ายกว่ามาก

ทางออกสุดท้ายของฉันพร้อมTLSรหัสที่จำเป็นสำหรับอุปกรณ์ 4.2+ มีลักษณะดังนี้:

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);
}

โปรดทราบว่าชุดของโปรโตคอลที่รองรับขึ้นอยู่กับการกำหนดค่าบนเซิร์ฟเวอร์ของคุณ


โซลูชันของคุณรองรับ API 14 หรือไม่
CoolMind

ไม่สามารถพูดได้อย่างแน่นอนทดสอบสิ่งนี้กับอุปกรณ์ API 16+ เท่านั้นใช้งานได้ดี
Fragment

1
Fragment ชื่อเล่นน่ารัก :) ฉันเห็นด้วยไม่สามารถเริ่มโปรแกรมจำลอง API 14 ได้ แต่โซลูชันของคุณใช้งานได้บน Android 7.0 (ที่มีปัญหา) และบน API 19
CoolMind

1
ขอบคุณฉันทดสอบแล้วมันใช้งานได้ วันนี้เปิดตัว API 19 จำลองอีกครั้งและมีการเพิ่มการแก้ปัญหาstackoverflow.com/a/51285550/2914140
CoolMind

12

ฉันพบวิธีแก้ปัญหาที่นี่ในลิงค์นี้

คุณต้องวางโค้ดด้านล่างในคลาสแอปพลิเคชัน Android ของคุณ และนั่นก็เพียงพอแล้ว ไม่จำเป็นต้องทำการเปลี่ยนแปลงใด ๆ ในการตั้งค่าชุดติดตั้งเพิ่มเติม มันช่วยวันของฉัน

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();
        }
    }
}

หวังว่านี่จะเป็นประโยชน์ ขอบคุณ.


ไม่ทำงานสำหรับฉัน!
morteza moradi

4

สิ่งนี้แก้ไขให้ฉัน:

เอกสาร Android สำหรับ SSLSocket ระบุว่ารองรับ TLS 1.1 และ TLS 1.2 ภายใน Android เริ่มต้น API ระดับ 16+ (Android 4.1, Jelly Bean) แต่โดยค่าเริ่มต้นจะถูกปิดใช้งาน แต่เริ่มต้นด้วย API ระดับ 20+ (Android 4.4 สำหรับนาฬิกา Kitkat Watch และ Android 5.0 สำหรับโทรศัพท์ Lollipop) จะเปิดใช้งาน แต่มันยากมากที่จะหาเอกสารเกี่ยวกับวิธีเปิดใช้งานสำหรับโทรศัพท์ที่ใช้ 4.1 เป็นต้น ในการเปิดใช้งาน TLS 1.1 และ 1.2 คุณต้องสร้าง SSLSocketFactory แบบกำหนดเองซึ่งจะทำการเรียกพร็อกซีทั้งหมดไปยังการใช้งาน SSLSocketFactory เริ่มต้น นอกจากนั้นเราต้องลบล้างเมธอด createSocket และ callsetEnabledProtocols ทั้งหมดบน SSLSocket ที่ส่งคืนเพื่อเปิดใช้งาน TLS 1.1 และ TLS 1.2 สำหรับตัวอย่างการใช้งานเพียงไปที่ลิงค์ด้านล่าง

Android 4.1 เปิดใช้งาน tls1.1 และ tls 1.2


2

ฉันมีปัญหารายงานข้อผิดพลาดนี้ด้วย รหัสของฉันอยู่ด้านล่าง

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();
}

ฉันมี Springboot เป็นแบ็กเอนด์และใช้ Android OKHttp เพื่อรับข้อมูล ข้อผิดพลาดร้ายแรงที่ฉันทำคือฉันใช้. url ( "https : //10.0.2.2: 8010 / getShopInfo / aaa")ในรหัสของ Android แต่แบ็กเอนด์ของฉันไม่ได้รับอนุญาตคำขอ https หลังจากที่ฉันใช้. url (" http : //10.0.2.2: 8010 / getShopInfo / aaa")รหัสของฉันก็ใช้ได้ดี ดังนั้นฉันต้องการจะบอกว่าข้อผิดพลาดของฉันไม่ใช่เวอร์ชันของโปรแกรมจำลอง แต่เกี่ยวกับโปรโตคอลการร้องขอ ฉันพบปัญหาอีกครั้งหลังจากที่ทำในสิ่งที่ผมพูด แต่มันก็เป็นอีกปัญหาหนึ่งและฉันแนบวิธีการแก้ปัญหาของปัญหาใหม่
ขอให้โชคดีครับท่าน!


1

สามารถทำซ้ำได้ก็ต่อเมื่อฉันใช้พร็อกซีบน genymotion (<4.4)

ตรวจสอบการตั้งค่าพร็อกซีของคุณในการตั้งค่า -> ไร้สายและเครือข่าย -> WiFi -> (ลองกด WiredSSID) -> แก้ไขเครือข่าย

เลือกแสดงตัวเลือกขั้นสูง: ตั้งค่าพร็อกซีเป็นไม่มี


1

เมื่อฉันได้รับข้อผิดพลาดนี้เป็นเพราะโปรโตคอล (เวอร์ชัน TLS) และ / หรือชุดการเข้ารหัสที่เซิร์ฟเวอร์รองรับไม่ได้เปิดใช้งาน (และอาจไม่ได้รับการสนับสนุนจาก) อุปกรณ์ สำหรับ API 16-19 รองรับ TLSv1.1 และ TLSv1.2 แต่ไม่ได้เปิดใช้งานตามค่าเริ่มต้น เมื่อฉันเปิดใช้งานสำหรับเวอร์ชันเหล่านี้ฉันยังคงได้รับข้อผิดพลาดเนื่องจากเวอร์ชันเหล่านี้ไม่รองรับการเข้ารหัสใด ๆ บนอินสแตนซ์ของ AWS CloudFront ของเรา

เนื่องจากไม่สามารถเพิ่มรหัสลงใน Android ได้เราจึงต้องเปลี่ยนเวอร์ชัน CloudFront จาก TLSv1.2_2018 เป็น TLSv1.1_2016 (ซึ่งยังรองรับ TLSv1.2 แต่ไม่จำเป็นต้องใช้) ซึ่งมีการเข้ารหัสสี่ตัวที่รองรับโดย Android เวอร์ชันก่อนหน้าซึ่งสองรุ่นยังถือว่าแข็งแกร่ง

เมื่อถึงจุดนั้นข้อผิดพลาดจะหายไปและมีการโทรออก (ด้วย TLSv1.2) เนื่องจากมีอย่างน้อยหนึ่งโปรโตคอลและอย่างน้อยหนึ่งรหัสที่อุปกรณ์และเซิร์ฟเวอร์ใช้ร่วมกัน

ดูตารางในหน้านี้เพื่อดูว่าโปรโตคอลและรหัสใดได้รับการสนับสนุนและเปิดใช้งานบน Android เวอร์ชันใด

ตอนนี้ Android พยายามใช้ SSLv3 ตามนัยของส่วน "sslv3 alert handshake failure" ของข้อความแสดงข้อผิดพลาดหรือไม่ ฉันสงสัยมัน; ฉันสงสัยว่านี่เป็นใยแมงมุมเก่าในไลบรารี SSL ที่ยังไม่ได้ล้างออก แต่ฉันไม่สามารถพูดได้อย่างแน่นอน

ในการเปิดใช้งาน TLSv1.2 (และ TLSv1.1) ฉันสามารถใช้งานได้ง่ายSSLSocketFactoryกว่าที่เห็นในที่อื่น ๆ (เช่นNoSSLv3SocketFactory) เพียงแค่ตรวจสอบให้แน่ใจว่าโปรโตคอลที่เปิดใช้งานรวมถึงโปรโตคอลที่รองรับทั้งหมดและการเข้ารหัสที่เปิดใช้งานนั้นรวมการเข้ารหัสที่รองรับทั้งหมด (อันหลังนี้ไม่จำเป็นสำหรับฉัน แต่อาจเป็นสำหรับคนอื่น ๆ ) - ดูconfigure()ที่ด้านล่าง หากคุณต้องการเปิดใช้งานเฉพาะโปรโตคอลล่าสุดคุณสามารถแทนที่socket.supportedProtocolsด้วยสิ่งต่างๆเช่นarrayOf("TLSv1.1", "TLSv1.2")(เช่นเดียวกันสำหรับการเข้ารหัส):

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
    }
}

คุณใช้มันอย่างไร?
CoolMind

0

ฉันแก้ไขปัญหาโดยสิ่งนี้: 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);
        }
    }
}

ชั้นหลัก:

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

คำตอบของฉันใกล้เคียงกับคำตอบข้างต้น แต่คุณต้องเขียนในชั้นเรียนโดยไม่เปลี่ยนแปลงอะไรเลย

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;
}

}

และใช้กับ 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();
                    }
                }
            }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.