accepting HTTPS connections with self-signed certificates

前端 未结 13 2084
小蘑菇
小蘑菇 2020-11-22 04:20

I\'m trying to make HTTPS connections, using HttpClient lib, but the problem is that, since the certificate isn\'t signed by a recognized Certificate Authority

相关标签:
13条回答
  • 2020-11-22 05:03

    I wrote small library ssl-utils-android to trust particular certificate on Android.

    You can simply load any certificate by giving the filename from assets directory.

    Usage:

    OkHttpClient client = new OkHttpClient();
    SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
    client.setSslSocketFactory(sslContext.getSocketFactory());
    
    0 讨论(0)
  • 2020-11-22 05:03

    None of these fixes worked for my develop platform targeting SDK 16, Release 4.1.2, so I found a workaround.

    My app stores data on server using "http://www.example.com/page.php?data=somedata"

    Recently page.php was moved to "https://www.secure-example.com/page.php" and I keep getting "javax.net.ssl.SSLException: Not trusted server certificate".

    Instead of accepting all certificates for only a single page, starting with this guide I solved my problem writing my own page.php published on "http://www.example.com/page.php"

    <?php
    
    caronte ("https://www.secure-example.com/page.php");
    
    function caronte($url) {
        // build curl request
        $ch = curl_init();
        foreach ($_POST as $a => $b) {
            $post[htmlentities($a)]=htmlentities($b);
        }
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));
    
        // receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $server_output = curl_exec ($ch);
        curl_close ($ch);
    
        echo $server_output;
    }
    
    ?>
    
    0 讨论(0)
  • 2020-11-22 05:04

    Jan 19th, 2020 Self Signed Certificate ISSUE FIX:

    To play video , image , calling webservice for any self signed certificate or connecting to any unsecured url just call this method before performing any action , it will fix your issue regarding certificate issue :

    KOTLIN CODE

      private fun disableSSLCertificateChecking() {
            val hostnameVerifier = object: HostnameVerifier {
                override fun verify(s:String, sslSession: SSLSession):Boolean {
                    return true
                }
            }
            val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
                override fun getAcceptedIssuers(): Array<X509Certificate> {
                    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                }
    
                //val acceptedIssuers:Array<X509Certificate> = null
                @Throws(CertificateException::class)
                override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
                }
                @Throws(CertificateException::class)
                override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
                }
            })
            try
            {
                val sc = SSLContext.getInstance("TLS")
                sc.init(null, trustAllCerts, java.security.SecureRandom())
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
                HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
            }
            catch (e: KeyManagementException) {
                e.printStackTrace()
            }
            catch (e: NoSuchAlgorithmException) {
                e.printStackTrace()
            }
        }
    
    0 讨论(0)
  • 2020-11-22 05:06

    If you have a custom/self-signed certificate on server that is not there on device, you can use the below class to load it and use it on client side in Android:

    Place the certificate *.crt file in /res/raw so that it is available from R.raw.*

    Use below class to obtain an HTTPClient or HttpsURLConnection which will have a socket factory using that certificate :

    package com.example.customssl;
    
    import android.content.Context;
    import org.apache.http.client.HttpClient;
    import org.apache.http.conn.scheme.PlainSocketFactory;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.scheme.SchemeRegistry;
    import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
    import org.apache.http.params.BasicHttpParams;
    import org.apache.http.params.HttpParams;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    
    public class CustomCAHttpsProvider {
    
        /**
         * Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
         * certificate.
         *
         * @param context       Application Context
         * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
         * @param allowAllHosts If true then client will not check server against host names of certificate.
         * @return Http Client.
         * @throws Exception If there is an error initializing the client.
         */
        public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
    
    
            // build key store with ca certificate
            KeyStore keyStore = buildKeyStore(context, certRawResId);
    
            // init ssl socket factory with key store
            SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
    
            // skip hostname security check if specified
            if (allowAllHosts) {
                sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
            }
    
            // basic http params for client
            HttpParams params = new BasicHttpParams();
    
            // normal scheme registry with our ssl socket factory for "https"
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
    
            // create connection manager
            ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
    
            // create http client
            return new DefaultHttpClient(cm, params);
        }
    
        /**
         * Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
         * certificate.
         *
         * @param urlString     remote url string.
         * @param context       Application Context
         * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
         * @param allowAllHosts If true then client will not check server against host names of certificate.
         * @return Http url connection.
         * @throws Exception If there is an error initializing the connection.
         */
        public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
                                                               boolean allowAllHosts) throws Exception {
    
            // build key store with ca certificate
            KeyStore keyStore = buildKeyStore(context, certRawResId);
    
            // Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
    
            // Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);
    
            // Create a connection from url
            URL url = new URL(urlString);
            HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
            urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
    
            // skip hostname security check if specified
            if (allowAllHosts) {
                urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
            }
    
            return urlConnection;
        }
    
        private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
            // init a default key store
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
    
            // read and add certificate authority
            Certificate cert = readCert(context, certRawResId);
            keyStore.setCertificateEntry("ca", cert);
    
            return keyStore;
        }
    
        private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
    
            // read certificate resource
            InputStream caInput = context.getResources().openRawResource(certResourceId);
    
            Certificate ca;
            try {
                // generate a certificate
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                ca = cf.generateCertificate(caInput);
            } finally {
                caInput.close();
            }
    
            return ca;
        }
    
    }
    

    Key points:

    1. Certificate objects are generated from .crt files.
    2. A default KeyStore is created.
    3. keyStore.setCertificateEntry("ca", cert) is adding certificate to key store under alias "ca". You modify the code to add more certificates (intermediate CA etc).
    4. Main objective is to generate a SSLSocketFactory which can then be used by HTTPClient or HttpsURLConnection.
    5. SSLSocketFactory can be configured further, for example to skip host name verification etc.

    More information at : http://developer.android.com/training/articles/security-ssl.html

    0 讨论(0)
  • 2020-11-22 05:08

    Maybe this will helpful... it works on java clients using self-signed certificates (there is no check of the certificate). Be careful and use it only for development cases because that is no secure at all!!

    How to ignore SSL certificate errors in Apache HttpClient 4.0

    Hope it will works on Android just adding HttpClient library... good luck!!

    0 讨论(0)
  • 2020-11-22 05:10

    I was frustrated trying to connect my Android App to my RESTful service using https. Also I was a bit annoyed about all the answers that suggested to disable certificate checking altogether. If you do so, whats the point of https?

    After googled about the topic for a while, I finally found this solution where external jars are not needed, just Android APIs. Thanks to Andrew Smith, who posted it on July, 2014

     /**
     * Set up a connection to myservice.domain using HTTPS. An entire function
     * is needed to do this because myservice.domain has a self-signed certificate.
     * 
     * The caller of the function would do something like:
     * HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
     * InputStream in = urlConnection.getInputStream();
     * And read from that "in" as usual in Java
     * 
     * Based on code from:
     * https://developer.android.com/training/articles/security-ssl.html#SelfSigned
     */
    public static HttpsURLConnection setUpHttpsConnection(String urlString)
    {
        try
        {
            // Load CAs from an InputStream
            // (could be from a resource or ByteArrayInputStream or ...)
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
    
            // My CRT file that I put in the assets folder
            // I got this file by following these steps:
            // * Go to https://littlesvr.ca using Firefox
            // * Click the padlock/More/Security/View Certificate/Details/Export
            // * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
            // The MainActivity.context is declared as:
            // public static Context context;
            // And initialized in MainActivity.onCreate() as:
            // MainActivity.context = getApplicationContext();
            InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
            Certificate ca = cf.generateCertificate(caInput);
            System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    
            // Create a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            // Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
    
            // Create an SSLContext that uses our TrustManager
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
    
            // Tell the URLConnection to use a SocketFactory from our SSLContext
            URL url = new URL(urlString);
            HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
            urlConnection.setSSLSocketFactory(context.getSocketFactory());
    
            return urlConnection;
        }
        catch (Exception ex)
        {
            Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
            return null;
        }
    }
    

    It worked nice for my mockup App.

    0 讨论(0)
提交回复
热议问题