Javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSLハンドシェイクが中止されました:SSLライブラリでの失敗、通常はプロトコルエラー


102

私はアンドロイドで次のコードを実行しようとしています

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でテストしましたが、うまく動きます。これの原因は何でしょうか?助けてください

スタックトレース

    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

それはどんな例外を与えていますか?スタックトレース?
ローンの侯爵

@PareshMayaniはい、Android 4.0を搭載した実際のデバイスでも例外が表示されます。
Bhavit S. Sengar 2015

@EJP質問を更新し、スタックトレースを追加しました。
Bhavit S. Sengar

これはジェリービーンとタグ付けされた唯一の質問です。もしかしてアンドロイド-4.2-ゼリーBeanを
Daniel Daranas、2015

回答:


120

私はwiresharkを使用してデータパケットを分析することにより、その解決策を見つけました。安全な接続を確立しているときに、AndroidがTLSv1からSSLv3にフォールバックしていたことわかりました。これはAndroidバージョン<4.4のバグであり、SSLv3プロトコルを[有効なプロトコル]リストから削除することで解決できます。NoSSLv3SocketFactory.javaというカスタムのsocketFactoryクラスを作成しました。これを使用して、ソケットファクトリを作成します。

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

これにより、SSLEngineでのTLSv1.2のサポートを含む、OpenSSLおよびJava Security Providerの新しいバージョンへのアプリへのアクセスが効果的に提供されます。新しいプロバイダーがインストールされたら、SSLv3、TLSv1、TLSv1.1、およびTLSv1.2を通常の方法でサポートするSSLEngineを作成できます。

    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でこれを取得しています
スカイネット

SSLCertificateSocketFactory.setHostname(Socket、String)メソッドを提供しないことでSNIを効果的に無効にするため、このアプローチは仮想ホストに接続するときに失敗するようです。openssl.exeとブラウザが問題なく接続する403を取得しています。不足しているSNIであることがわかります。
JaroslavZáruba16年

2
ボレーでこれをどのように使用できますか?
uniruddh 16

1
Android API 19でこのエラーが発生しますjavax.net.ssl.SSLProtocolException:読み取りエラー:ssl = 0xb83d7120:SSLライブラリの障害、通常はプロトコルエラー
Rukmal Dias

117

シナリオ

Android 5.0より前のバージョンのAndroidを実行しているデバイスでSSLHandshake例外が発生しました。私の使用例では、クライアント証明書を信頼するTrustManagerも作成したいと思いました。

クライアントのサポートされているプロトコルのリストからSSLv3を削除するためにNoSSLv3SocketFactoryおよびNoSSLv3Factoryを実装しましたが、これらのソリューションのどちらも機能しませんでした。

私が学んだいくつかのこと:

  • Android 5.0より古いデバイスでは、TLSv1.1およびTLSv1.2プロトコルはデフォルトで有効になっていません。
  • Android 5.0より前のデバイスでは、SSLv3プロトコルはデフォルトで無効になっていません。
  • SSLv3は安全なプロトコルではないため、接続を確立する前に、クライアントのサポートされているプロトコルのリストから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の投稿を見つけました。SSLソケットで有効にする暗号スイートはどれですか。


1
Google Play開発者サービスを実行しているデバイスの数について公開されている統計を知りません。私が見つけた最新の数字は、Sundar PichaiのIO 2014の講演で、Androidデバイスの93%にPlay Servicesの最新バージョンが搭載されていると彼は言っています。手動の方法に関しては、すべての手動の​​方法がうまくいかなかったときにこの解決策にたどり着きました。ユーザーにとってネットワークセキュリティが重要でない場合、ユーザーがPlayサービスのインストールを拒否すると、常にHTTPにフォールバックする可能性があります。私たちのアプリでは、互換性とセキュリティのトレードオフを検討しました。Playサービスの更新を実施します。
モーリスギャビン

3
中国でのGoogle Play開発者サービスのサポートは非​​常に限られています。ターゲットオーディエンスによっては、知っておくと役に立ちます。しかし、まあ、あなたがグーグルプレイを介して配布する場合、このオーディエンスはすでに見逃されています。
jayeffkay

3
ソリューションを機能させるには、この依存関係を追加してください。「com.google.android.gms:play-services-auth:10.2.0」をコンパイルします
Pradeep Chakravarti Gudipati

3
ProviderInstaller.installIfNeeded(this);を追加します。ApplicationのonCreate()への一部がうまくいきました!ありがとう:-)
Kelevandos 2017年

1
ここで間違いなく最も役立つ答えです。そのような貴重な助けをありがとう。
BurakKarakuş18年

50

また、デフォルトで有効になっていないAndroid 4.0デバイスに対してTLS v1.2を強制できることも知っておく必要があります。

このコードをアプリケーションファイルのonCreate()に配置します

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 2019

1
@mayur gangurdeに感謝します。これは、play services auth gradle、実装 'com.google.android.gms:play-services-auth:16.0.1'を追加した後の仕事用です
Basant

完璧に働きました。テストと試行の時間を節約してくれてありがとう。
Ninad Desai

とても便利です。どうもありがとう!
Caspar Geerlings

15

以前は、カスタムSSLFactory実装でこの問題も解決しましたが、OkHttpドキュメントによると、解決策ははるかに簡単です。

TLS4.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

確かに言うことはできません。これは16以上のAPIデバイスでのみテストされ、正常に動作します。
フラグメント

1
フラグメント、かわいいニックネーム:)私は同意するが、でも、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();
        }
    }
}

これがお役に立てば幸いです。ありがとうございました。


4

これは私のためにそれを解決しました:

SSLSocketのAndroidドキュメントには、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を作成する必要があります。さらに、TLS 1.1およびTLS 1.2を有効にするために、返されたSSLSocketですべてのcreateSocketメソッドとcallsetEnabledProtocolsをオーバーライドする必要があります。実装例については、以下のリンクをクリックしてください。

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を使用して情報を取得しています。私が犯した重大な間違いは、Androidのコードで.url(" https://10.0.2.2:8010 / getShopInfo / aaa")を使用することでした。しかし、私のバックエンドはhttpsリクエストを許可されていません。私が使用した後にする.urlを( " のhttp://10.0.2.2:8010 / getShopInfo / AAA") 、その後、私のコードはうまくいきました。だから、私の間違いはエミュレータのバージョンではなく、リクエストプロトコルに関するものだと言いたいです。私が言ったことをした後で別の問題に遭遇しましたが、それは別の問題であり、新しい問題のresolveメソッドをアタッチします
グッドラック!ガイ!


1

genymotion(<4.4)でプロキシを使用した場合にのみ再現可能でした。

設定->ワイヤレスとネットワーク-> WiFi->(Long Press WiredSSID)->ネットワークの変更でプロキシ設定を確認してください

詳細オプションの表示を選択します。プロキシ設定をNONEに設定します。


1

このエラーが発生したのは、サーバーでサポートされているプロトコル(TLSバージョン)または暗号スイート、あるいはその両方がデバイスで有効になっていないためです(サポートされていない可能性もあります)。API 16-19では、TLSv1.1とTLSv1.2がサポートされていますが、デフォルトでは有効になっていません。これらのバージョンでそれらを有効にしても、これらのバージョンはAWS CloudFrontのインスタンスの暗号をサポートしていないため、エラーが発生します。

Androidに暗号を追加することはできないため、CloudFrontのバージョンをTLSv1.2_2018からTLSv1.1_2016に切り替える必要がありました(TLSv1.2は引き続きサポートされていますが、必要はありません)。以前のAndroidバージョン。そのうち2つはまだ強力と見なされています。

その時点で、デバイスとサーバーが共有する少なくとも1つのプロトコルと少なくとも1つの暗号があったため、エラーはなくなり、コールは(TLSv1.2で)通過しました。

このページの表を参照してください、Androidのどのバージョンでサポートされ、有効にされているプロトコルと暗号を確認してください。

エラーメッセージの「sslv3アラートハンドシェイクの失敗」の部分が示すように、Androidは実際にSSLv3を使用しようとしていましたか?疑わしい; これは、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.