1

在一些旧的 Android 版本 (< API 21) 上,只有SSLv3并且TLSv1可用:

在此处输入图像描述

服务器接受最小值TLSv1,握手SSL被拒绝。因此,为了让 Glide 正确加载图像,我使用了一个自定义 okhttp 客户端和一个使用TLSv1.

@GlideModule
public class TlsGlideModule extends AppGlideModule {

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        super.registerComponents(context, glide, registry);

        OkHttpClient.Builder client = new OkHttpClient.Builder();
        enableTls1(client);
        
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client.build()));
    }
}

private static void enableTls1(OkHttpClient.Builder client) {
    SSLContext sc = SSLContext.getInstance("TLSv1");
    sc.init(null, null, null);
    client.sslSocketFactory(new TlsSocketFactory(sc.getSocketFactory()));

    ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
            .tlsVersions(TlsVersion.TLS_1_0)
            .build();

    List<ConnectionSpec> specs = new ArrayList<>();
    specs.add(cs);
    client.connectionSpecs(specs);
}

public class TlsSocketFactory extends SSLSocketFactory {
    private static final String[] allowedTlsVersions = {"TLSv1"};

    private final SSLSocketFactory delegate;

    public TlsSocketFactory(SSLSocketFactory base) {
        this.delegate = base;
    }

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

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

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

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

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

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

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

    private Socket patch(Socket s) {
        if (s instanceof SSLSocket) {
            ((SSLSocket) s).setEnabledProtocols(allowedTlsVersions);
        }
        return s;
    }
}

当我在这些方法中设置断点时,我看到它们在 Glide 初始化时被调用,但图像仍然没有加载,错误仍然是:

Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb987bb88: Failure in SSL library, usually a protocol error
    error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (third_party/openssl/boringssl/src/ssl/tls_record.cc:592 0xb980d4d8:0x00000001)
    error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (third_party/openssl/boringssl/src/ssl/handshake.cc:589 0x8696ec03:0x00000000)
        at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        ...

如果我删除上面的所有代码并在应用程序启动时调用它,图像加载正常:

ProviderInstaller.installIfNeeded(App.getInstance().getApplicationContext());

但是根据SSLContext,该设备已经TLSv1在设备上可用,所以我更喜欢没有 Google Play Services 依赖项。

这是为什么?

4

1 回答 1

0

你需要告诉 OkHttp 使用它不太安全的 ConnectionSpec,COMPATIBLE_TLS。

OkHttpClient client = new OkHttpClient.Builder()
    .connectionSpecs(Arrays.asList(ConnectionSpec.COMPATIBLE_TLS))
    .build();

https://square.github.io/okhttp/https/

于 2020-06-29T23:52:08.763 回答