【问题标题】:Picasso Image Loading https with self signed certificates [duplicate]毕加索图像加载带有自签名证书的 https [重复]
【发布时间】:2020-04-14 02:01:35
【问题描述】:

我正在研究毕加索以将图像显示到我的 android 活动中。但是我的服务器有 HTTPS 的自签名证书,这就是我给我以下错误的原因:

 com.squareup.picasso.NetworkRequestHandler$ResponseException: HTTP 504

我之前修复了这个问题以进行改造,现在我在答案中发布了解决方案:您需要使用以下代码如下的 RetrofitClient 类并在方法trustedCertificatesInputStream 中更新您的证书:

我希望这会拯救某人的一天:)

【问题讨论】:

    标签: android ssl picasso


    【解决方案1】:
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.GeneralSecurityException;
    import java.security.KeyStore;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.util.Arrays;
    import java.util.Collection;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    import javax.net.ssl.X509TrustManager;
    
    import okhttp3.OkHttpClient;
    import okhttp3.Response;
    import okhttp3.logging.HttpLoggingInterceptor;
    import okio.Buffer;
    import retrofit2.Retrofit;
    import retrofit2.converter.gson.GsonConverterFactory;
    
    public class RetrofitClient {
    
    
        public static Retrofit getApiClient(String baseUrl) {
    
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    
    
            X509TrustManager trustManager;
            SSLSocketFactory sslSocketFactory;
            try {
                trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, new TrustManager[]{trustManager}, null);
                sslSocketFactory = sslContext.getSocketFactory();
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
    
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(interceptor)
                    .sslSocketFactory(sslSocketFactory, trustManager)
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .build();
    
    
    
    
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    
            Log.e("RetrofitClient", baseUrl);
    
            return retrofit;
    
        }
    
    
    
        public static OkHttpClient okClient(){
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    
    
            X509TrustManager trustManager;
            SSLSocketFactory sslSocketFactory;
            try {
                trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, new TrustManager[]{trustManager}, null);
                sslSocketFactory = sslContext.getSocketFactory();
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }
    
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(interceptor)
                    .sslSocketFactory(sslSocketFactory, trustManager)
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .build();
            return client;
    
        }
    
    
        private static X509TrustManager trustManagerForCertificates(InputStream in)
                throws GeneralSecurityException {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
            if (certificates.isEmpty()) {
                throw new IllegalArgumentException("expected non-empty set of trusted certificates");
            }
    
            // Put the certificates a key store.
            char[] password = "password".toCharArray(); // Any password will work.
            KeyStore keyStore = newEmptyKeyStore(password);
            int index = 0;
            for (Certificate certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificate);
            }
    
            // Use it to build an X509 trust manager.
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                    KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, password);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                    TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:"
                        + Arrays.toString(trustManagers));
            }
            return (X509TrustManager) trustManagers[0];
        }
    
        private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
            try {
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                InputStream in = null; // By convention, 'null' creates an empty key store.
                keyStore.load(in, password);
                return keyStore;
            } catch (IOException e) {
                throw new AssertionError(e);
            }
        }
    
    
        private static InputStream trustedCertificatesInputStream() {
            // PEM files for root certificates of Comodo and Entrust. These two CAs are sufficient to view
            // https://publicobject.com (Comodo) and https://squareup.com (Entrust). But they aren't
            // sufficient to connect to most HTTPS sites including https://godaddy.com and https://visa.com.
            // Typically developers will need to get a PEM file from their organization's TLS administrator.
            String comodoRsaCertificationAuthority = "-----BEGIN CERTIFICATE-----\n" +
                    "MIIGHDCCBASgAwIBAgIJAL9YjcpQAkTLMA0GCSqGSIb3DQEBCwUAMIGiMQswCQYD\n" +
                    "VQQGEwJQSzEPMA0GA1UECAwGUHVuamFiMQ8wDQYDVQQHDAZNdWx0YW4xGzAZBgNV\n" +
    
    
                    "j2pjtSNqRIxmXE1ZtOj4f/RxUMoYUSg3AKvG0zRq1WgpKPgqkSi4i3AUI7bXoX7B\n" +
                    "ayGxYS6Dofx+LfQFugB3HVmn+7lpY/wb1Dp3z/wmi0xT+8BZL/qvI4ISS4mAPJ9d\n" +
                    "77JwSrQ40qnuWXkoJwC8ubWPP9bQWxolzW2rFn2yRyz9Po/tOYfpV/hhDNbuumxW\n" +
                    "MHVM3Z1pwTUM1xz8RlFE9uJOGVgMX/iikqZ1EMZ6QwIvXZ7Lcpd0Ov09xeeyIx0x\n" +
                    "Gj/t9/7PdrDTkTUG3qZ/UJNqcD2dKBY5E7bZn5QhLSJBTva9vCC/N2i4+i77K/Cy\n" +
    
                    "X/uaAUlYfUhBD4uet2C88syqtkW0+Vb0MuTO4sO1YSE=\n" +
                    "-----END CERTIFICATE-----\n";
    
            return new Buffer()
                    .writeUtf8(comodoRsaCertificationAuthority)
                    .inputStream();
        }
    }
    

    然后用它来加载你的 https 图像:

    
    // let's change the standard behavior before we create the Picasso instance
    // for example, let's switch out the standard downloader for the OkHttpClient
               picassoBuilder.downloader(new OkHttp3Downloader(RetrofitClient.okClient()));
    
    // Picasso.Builder creates the Picasso object to do the actual requests
               Picasso picasso = picassoBuilder.build();
    
    
    
               Picasso.setSingletonInstance(picasso); //apply to default singleton instance
               picasso.get().load("https://xxxxxxxxxx.xxx/uploads/16_registration_1575959841.jpeg").noPlaceholder().fit().centerCrop()
                       .into(imageView, new com.squareup.picasso.Callback() {
                           @Override
                           public void onSuccess() {
                               Log.e("image Loade","image succssfully loaded");
                           }
    
                           @Override
                           public void onError(Exception e) {
                               Log.e("image Loade",e.toString());
                           }
                       });
           }
    
    

    【讨论】:

    • 我知道。但是没有任何其他解决方案可以使用自签名证书。 @SteffenUllrich,如果您有任何想法,请分享
    • @SteffenUllrich 如果我们在 public boolean verify(String hostname, SSLSession session) { if (hostname.equals("xxxx.cxx")) return true;else return false; }
    • 如果你真的需要使用自签名证书那么你需要检查你得到的证书是否和预期的完全一样。仅仅检查主题将无济于事,因为攻击者可以创建具有相同主题的证书。我已将问题标记为重复,其他问题的答案实际上解释了如何正确执行此操作。
    • @SteffenUllrich 我试图暗示您提供的答案,但不推荐使用 .sslSocketFactory(sslContext.getSocketFactory()) 。它需要信任管理器对象。你能指导我怎么做吗?或任何其他样本?
    猜你喜欢
    • 1970-01-01
    • 2020-02-22
    • 2014-05-05
    • 2020-04-24
    • 2014-09-26
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多