aceitando conexões HTTPS com certificados autoassinados

153

Estou tentando fazer conexões HTTPS usando HttpClientlib, mas o problema é que, como o certificado não é assinado por uma Autoridade de Certificação (CA) reconhecida como Verisign , GlobalSIgn , etc., listado no conjunto de Certificados confiáveis ​​do Android, Eu continuo recebendo javax.net.ssl.SSLException: Not trusted server certificate.

Vi soluções em que você simplesmente aceita todos os certificados, mas e se eu quiser perguntar ao usuário?

Quero obter uma caixa de diálogo semelhante à do navegador, permitindo que o usuário decida continuar ou não. De preferência, eu gostaria de usar o mesmo armazenamento de certificados que o navegador. Alguma ideia?

Morten
fonte
Esta solução Aceita funcionou para mim- stackoverflow.com/questions/2642777/…
Venkatesh

Respostas:

171

A primeira coisa que você precisa fazer é definir o nível de verificação. Tais níveis não são tanto:

  • ALLOW_ALL_HOSTNAME_VERIFIER
  • BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  • STRICT_HOSTNAME_VERIFIER

Embora o método setHostnameVerifier () seja obsoleto para a nova biblioteca apache, a versão no Android SDK é normal. E assim nós pegamos ALLOW_ALL_HOSTNAME_VERIFIERe colocamos na fábrica de métodosSSLSocketFactory.setHostnameVerifier() .

Em seguida, você precisa definir nossa fábrica para o protocolo como https. Para fazer isso, basta chamar oSchemeRegistry.register() método

Então você precisa criar um DefaultHttpClientcomSingleClientConnManager . Também no código abaixo, você pode ver que, por padrão, também usará nossa flag ( ALLOW_ALL_HOSTNAME_VERIFIER) pelo métodoHttpsURLConnection.setDefaultHostnameVerifier()

O código abaixo funciona para mim:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client = new DefaultHttpClient();

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

// Set verifier     
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request
final String url = "https://encrypted.google.com/";
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
Nikolay Moskvin
fonte
6
Infelizmente, não consigo fazer esse código funcionar, ainda recebo o "Certificado de servidor não confiável". Existem permissões extras que tenho que definir para que funcione?
Juriy
1
Este código não aceita apenas todos os certificados? Eu preciso de um pop-up para aceitá-lo.
Morten
3
Estou usando org.apache.http.conn.ssl.SSLSocketFactorypor que eu quero usar javax.net.ssl.HttpsURLConnection??
Alguém em algum lugar
9
Você pode explicar como esse código é melhor do que desativar totalmente a verificação de certificado? Não estou familiarizado com a API SSL do Android, mas, à primeira vista, isso parece completamente inseguro contra invasores ativos.
CodesInChaos
3
Eu sugeriria o uso de ThreadSafeClientConnManager em vez de SingleClientConnManager
Farm
124

As etapas principais a seguir são necessárias para obter uma conexão segura das autoridades de certificação que não são consideradas confiáveis ​​pela plataforma Android.

Conforme solicitado por muitos usuários, espelhei as partes mais importantes do artigo do meu blog aqui:

  1. Pegue todos os certificados necessários (raiz e quaisquer CAs intermediárias)
  2. Crie um keystore com keytool e o provedor BouncyCastle e importe os certificados
  3. Carregue o keystore no seu aplicativo Android e use-o para as conexões seguras (eu recomendo usar o Apache HttpClient em vez do padrão java.net.ssl.HttpsURLConnection(mais fácil de entender, mais eficiente)

Pegue os certs

É necessário obter todos os certificados que constroem uma cadeia a partir do certificado do terminal até a CA raiz. Isso significa que qualquer certificado CA intermediário (se presente) e também o certificado CA raiz. Você não precisa obter o certificado do terminal.

Crie o keystore

Faça o download do provedor BouncyCastle e armazene-o em um local conhecido. Verifique também se você pode chamar o comando keytool (geralmente localizado na pasta bin da instalação do JRE).

Agora importe os certificados obtidos (não importe o certificado do terminal) para um keystore no formato BouncyCastle.

Não testei, mas acho importante a ordem de importação dos certificados. Isso significa, importe primeiro o certificado CA intermediário mais baixo e depois o certificado CA raiz.

Com o comando a seguir, um novo keystore (se ainda não estiver presente) com a senha mysecret será criado e o certificado CA intermediário será importado. Também defini o provedor BouncyCastle, onde ele pode ser encontrado no meu sistema de arquivos e no formato keystore. Execute este comando para cada certificado na cadeia.

keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Verifique se os certificados foram importados corretamente no keystore:

keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Deve gerar toda a cadeia:

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Agora você pode copiar o keystore como um recurso bruto no seu aplicativo Android em res/raw/

Use o keystore no seu aplicativo

Primeiro, precisamos criar um Apache HttpClient personalizado que use nosso keystore para conexões HTTPS:

import org.apache.http.*

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
            sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

Criamos nosso HttpClient personalizado, agora podemos usá-lo para conexões seguras. Por exemplo, quando fazemos uma chamada GET para um recurso REST:

// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();

É isso aí ;)

saxos
fonte
8
Isso é útil apenas para obter certificados antes de enviar seu aplicativo. Realmente não ajuda os usuários a aceitarem seus próprios certificados. para sua aplicação
Difuso
Oi pessoal Alguém pode me dizer o processo de validação do keystore com armazenamento confiável para a implementação acima ??? obrigado antecipadamente ..
andriod_testing
Isso funcionou bem ... mas agora estou enfrentando um problema ao reescrever o certificado no servidor. Parece estranho que sempre que eu atualizar o certificado no meu servidor, o repositório do cliente também deve ser atualizado. Tem que haver uma maneira melhor: |
BPN
Resposta Gr8, eu sugeriria o uso de ThreadSafeClientConnManager em vez de SingleClientConnManager
Farm
Eu adicionei /res/raw/mykeystore.bks, embora não seja possível resolver a referência a ele. como resolver isso?
uniruddh
16

Se você possui um certificado personalizado / autoassinado no servidor que não existe no dispositivo, pode usar a classe abaixo para carregá-lo e usá-lo no lado do cliente no Android:

Coloque o *.crtarquivo de certificado em/res/raw para que esteja disponível emR.raw.*

Use a classe abaixo para obter um HTTPClientou HttpsURLConnectionque terá uma fábrica de soquetes usando esse certificado:

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

}

Pontos chave:

  1. Certificate objetos são gerados a partir de .crt arquivos.
  2. Um padrão KeyStoreé criado.
  3. keyStore.setCertificateEntry("ca", cert)está adicionando certificado ao armazenamento de chaves com o alias "ca". Você modifica o código para adicionar mais certificados (CA intermediária, etc.).
  4. O objetivo principal é gerar um SSLSocketFactoryque possa ser usado por HTTPClientou HttpsURLConnection.
  5. SSLSocketFactory pode ser configurado ainda mais, por exemplo, para ignorar a verificação do nome do host etc.

Mais informações em: http://developer.android.com/training/articles/security-ssl.html

SD
fonte
Onde posso obter .crtarquivos? Baixar de um servidor?
Zionpi 24/08/2015
@zionpi O arquivo de certificado será o mesmo usado pelo servidor habilitado para TLS ao qual você está se conectando.
SD
Obrigado! Isso foi tão fácil!
kapil Thadani
@ SD Como posso usar o arquivo .P12 em vez de .crt?
Rakesh R Nair
Eu tenho um resfriado dúvida similar você por favor me ajude stackoverflow.com/questions/57389622/...
StezPet
8

Fiquei frustrado ao tentar conectar meu aplicativo Android ao meu serviço RESTful usando https. Também fiquei um pouco irritado com todas as respostas que sugeriram desativar completamente a verificação de certificado. Se você fizer isso, qual é o sentido de https?

Depois de pesquisar um pouco sobre o assunto por um tempo, finalmente encontrei esta solução em que frascos externos não são necessários, apenas APIs do Android. Agradecimentos a Andrew Smith, que publicou em julho de 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;
    }
}

Funcionou bem para o meu aplicativo de maquete.

Gonzalo Fernández
fonte
X509Certifique qual devo importar java ou javax?
Siddharth
Importeiimport java.security.cert.X509Certificate;
Gonzalo Fernández
Obrigado por este .é realmente um trabalho e simples
Anuradhe Dilshan
6

A resposta principal não funcionou para mim. Após alguma investigação, encontrei as informações necessárias em "Desenvolvedor Android": https://developer.android.com/training/articles/security-ssl.html#SelfSigned

A criação de uma implementação vazia do X509TrustManager fez o truque:

private static class MyTrustManager implements X509TrustManager
{

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
    {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }

}

...

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    TrustManager[] tmlist = {new MyTrustManager()};
    context.init(null, tmlist, null);
    conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
    throw new IOException(e);
} catch (KeyManagementException e)
{
    throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();

Esteja ciente de que esta implementação vazia do TustManager é apenas um exemplo e usá-lo em um ambiente produtivo causaria uma grave ameaça à segurança!

Markus Lenger
fonte
1
apenas fyi - idk, se fosse assim na época, mas eles parecem desencorajar fortemente essa abordagem agora (veja a nota)
Saik Caskey
6

O Google recomenda o uso do Android Volley para conexões HTTP / HTTPS , pois isso HttpClientfoi preterido. Então, você sabe a escolha certa :).

E também NUNCA NUKE Certificados SSL (NUNCA !!!).

Nuke Certificados SSL é totalmente contra o objetivo do SSL, que está promovendo a segurança . Não há sentido em usar SSL, se você planeja bombardear todos os certificados SSL que vêm. Uma solução melhor seria, sem usar SSL, ou uma solução melhor, seria criar um personalizado TrustManagerno seu App + usando o Android Volley para conexões HTTP / HTTPS.

Aqui está uma Gist que eu criei, com um LoginApp básica, realizando conexões HTTPS, usando um certificado auto-assinado no lado do servidor, aceito na App.

Aqui também está outra lista essencial que pode ajudar, para criar certificados SSL autoassinados para configurar no seu servidor e também usar o certificado no seu aplicativo. Muito importante: você deve copiar o arquivo .crt gerado pelo script acima, para o diretório "bruto" do seu projeto Android.

ivanleoncz
fonte
Olá Ivan, nunca trabalhei com certificados SSL. Você gostaria de elaborar um pouco, como obtenho o arquivo .crt?
jlively
Oi Jively! Entendo. Sim, claro. Mas primeiro, você se importaria de dar uma olhada no segundo Gist que mencionei acima? Coloquei dois arquivos nessa Gist: um é o arquivo usado pelo script e o outro, é o próprio script, que usa o binário "openssl" para ler o arquivo e, em seguida, criar o arquivo que contém o certificado SSL ( .crt). Deixe-me saber se você conseguiu entender a coisa toda. Saudações :).
precisa saber é o seguinte
Hmm, sim, eu olhei para essas 2 gists, mas não consigo entender como usá-las?
jlively
4

Veja como você pode adicionar certificados adicionais ao KeyStore para evitar esse problema: Confiando em todos os certificados usando HttpClient sobre HTTPS

Ele não solicitará o usuário como você solicitou, mas tornará menos provável que o usuário encontre um erro "Certificado de servidor não confiável".

empapar
fonte
Apenas para fins de teste, você não pode publicar um aplicativo na Play Store com este truque, porque ele vai ser rejeitado
ariel
3

Maneira mais simples de criar certificado SSL

Abra o Firefox (suponho que também seja possível com o Chrome, mas é mais fácil para mim com o FF)

Visite seu site de desenvolvimento com um certificado SSL autoassinado.

Clique no certificado (ao lado do nome do site)

Clique em "Mais informações"

Clique em "Ver certificado"

Clique em "Detalhes"

Clique em "Exportar ..."

Escolha "Certificado X.509 com cadeia (PEM)", selecione a pasta e o nome para salvá-lo e clique em "Salvar"

Vá para a linha de comando, para o diretório em que você baixou o arquivo pem e execute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"

Copie o arquivo .crt para a raiz da pasta / sdcard dentro do seu dispositivo Android Dentro do seu dispositivo Android, Configurações> Segurança> Instalar do armazenamento.

Ele deve detectar o certificado e permitir que você o adicione ao dispositivo Navegue até o site de desenvolvimento.

Na primeira vez, você deverá confirmar a exceção de segurança. Isso é tudo.

O certificado deve funcionar com qualquer navegador instalado no seu Android (navegador, Chrome, Opera, Dolphin ...)

Lembre-se de que, se você estiver exibindo seus arquivos estáticos de um domínio diferente (todos nós somos cadelas de velocidade da página), também precisará adicionar o certificado para esse domínio.

Mani kandan
fonte
2

Eu escrevi uma pequena biblioteca ssl-utils-android para confiar em um certificado específico no Android.

Você pode simplesmente carregar qualquer certificado, fornecendo o nome do arquivo no diretório de ativos.

Uso:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
klimat
fonte
1

Nenhuma dessas correções funcionou para minha plataforma de desenvolvimento direcionada ao SDK 16, versão 4.1.2, por isso encontrei uma solução alternativa.

Meu aplicativo armazena dados no servidor usando " http://www.example.com/page.php?data=somedata "

Recentemente, o page.php foi movido para " https://www.secure-example.com/page.php " e continuo recebendo "javax.net.ssl.SSLException: certificado de servidor não confiável".

Em vez de aceitar todos os certificados para apenas uma única página, começando com este guia , resolvi meu problema escrevendo meu próprio page.php publicado em " 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;
}

?>
Rudy
fonte
1

19 de janeiro de 2020 - Certificado autoassinado FIXO DE EMISSÃO:

Para reproduzir vídeo, imagem, chamar o serviço da web para obter qualquer certificado autoassinado ou conectar-se a qualquer URL não seguro, basta chamar esse método antes de executar qualquer ação, o problema será resolvido com relação ao certificado:

CÓDIGO KOTLIN

  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()
        }
    }
Shobhakar Tiwari
fonte
0

Talvez isso seja útil ... funciona em clientes java usando certificados autoassinados (não há verificação do certificado). Tenha cuidado e use-o apenas para casos de desenvolvimento, porque isso não é seguro!

Como ignorar erros de certificado SSL no Apache HttpClient 4.0

Espero que funcione no Android apenas adicionando a biblioteca HttpClient ... boa sorte !!

EmP
fonte
1
Sem ele não funciona no Android, uma vez que se baseia em métodos obsoletos que não estão presentes na variante Android :-(
kellyfj
0

Esse é um problema resultante da falta de suporte ao SNI (Server Name Identification) em A, ndroid 2.x. Eu estava lutando com esse problema por uma semana até me deparar com a seguinte pergunta, que não apenas fornece uma boa base do problema, mas também fornece uma solução funcional e eficaz sem quaisquer falhas de segurança.

Erro 'No peer certificate' no Android 2.3, mas NÃO no 4

alumat
fonte