Je fais un message https et je reçois une exception de certificat de serveur non approuvé d'exception SSL. Si je fais du http normal, cela fonctionne parfaitement. Dois-je accepter le certificat du serveur d'une manière ou d'une autre?
Je fais un message https et je reçois une exception de certificat de serveur non approuvé d'exception SSL. Si je fais du http normal, cela fonctionne parfaitement. Dois-je accepter le certificat du serveur d'une manière ou d'une autre?
Réponses:
Je fais une supposition, mais si vous voulez qu'une véritable poignée de main se produise, vous devez informer Android de votre certificat. Si vous voulez simplement accepter quoi qu'il arrive, utilisez ce pseudo-code pour obtenir ce dont vous avez besoin avec le client HTTP Apache:
SchemeRegistry schemeRegistry = new SchemeRegistry ();
schemeRegistry.register (new Scheme ("http",
PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
new CustomSSLSocketFactory (), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
params, schemeRegistry);
return new DefaultHttpClient (cm, params);
CustomSSLSocketFactory:
public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory
{
private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();
public CustomSSLSocketFactory ()
{
super(null);
try
{
SSLContext context = SSLContext.getInstance ("TLS");
TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
context.init (null, tm, new SecureRandom ());
FACTORY = context.getSocketFactory ();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public Socket createSocket() throws IOException
{
return FACTORY.createSocket();
}
// TODO: add other methods like createSocket() and getDefaultCipherSuites().
// Hint: they all just make a call to member FACTORY
}
FullX509TrustManager est une classe qui implémente javax.net.ssl.X509TrustManager, mais aucune des méthodes n'effectue réellement de travail, obtenez un exemple ici .
Bonne chance!
FullX509TrustManager
C'est ce que je fais. Il ne vérifie tout simplement plus le certificat.
// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
/**
* Trust every server - dont check for any certificate
*/
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
et
HttpURLConnection http = null;
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
. J'ai également essayé de remplacer TLS
par SSL
mais cela n'a pas aidé. S'il vous plaît, aidez-moi, merci
En essayant de répondre à cette question, j'ai trouvé un meilleur tutoriel. Avec lui, vous n'avez pas à compromettre la vérification du certificat.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* Je n'ai pas écrit ceci mais merci à Bob Lee pour le travail
Vous pouvez également consulter mon article de blog, très similaire à crazybobs.
Cette solution ne compromet pas non plus la vérification des certificats et explique comment ajouter les certificats de confiance dans votre propre keystore.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
Gracieuseté de Maduranga
Lors du développement d'une application utilisant https, votre serveur de test ne dispose pas d'un certificat SSL valide. Parfois, le site Web utilise un certificat auto-signé ou le site Web utilise un certificat SSL gratuit. Donc, si vous essayez de vous connecter au serveur en utilisant ApacheHttpClient
, vous obtiendrez une exception indiquant que le "pair non authentifié". Bien que faire confiance à tous les certificats d'un logiciel de production ne soit pas une bonne pratique, vous devrez peut-être le faire en fonction de la situation. Cette solution résout l'exception provoquée par «pair non authentifié».
Mais avant de passer à la solution, je dois vous avertir que ce n'est pas une bonne idée pour une application de production. Cela enfreindra l'objectif de l'utilisation d'un certificat de sécurité. Donc, sauf si vous avez une bonne raison ou si vous êtes sûr que cela ne posera aucun problème, n'utilisez pas cette solution.
Normalement, vous créez un HttpClient
comme celui-ci.
HttpClient httpclient = new DefaultHttpClient();
Mais vous devez changer la façon dont vous créez le HttpClient.
Vous devez d'abord créer une extension de classe org.apache.http.conn.ssl.SSLSocketFactory
.
import org.apache.http.conn.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
Ensuite, créez une méthode comme celle-ci.
public HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
Ensuite, vous pouvez créer le fichier HttpClient
.
HttpClient httpclient = getNewHttpClient();
Si vous essayez d'envoyer une demande de publication sur une page de connexion, le reste du code ressemblerait à ceci.
private URI url = new URI("url of the action of the form");
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", "user"));
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Vous obtenez la page html dans InputStream. Ensuite, vous pouvez faire ce que vous voulez avec la page html renvoyée.
Mais ici, vous serez confronté à un problème. Si vous souhaitez gérer une session à l'aide de cookies, vous ne pourrez pas le faire avec cette méthode. Si vous souhaitez obtenir les cookies, vous devrez le faire via un navigateur. Alors seulement vous recevrez des cookies.
Si vous utilisez un certificat StartSSL ou Thawte, il échouera pour Froyo et les versions antérieures. Vous pouvez utiliser le référentiel CAcert d' une version plus récente au lieu d'approuver chaque certificat.
Aucun de ceux-ci n'a fonctionné pour moi (aggravé par le bogue Thawte également). Finalement, je l'ai réparé avec l'acceptation SSL auto-signé sur Android et la gestion SSL personnalisée a cessé de fonctionner sur Android 2.2 FroYo
Aucune de ces réponses n'a fonctionné pour moi, voici donc un code qui fait confiance à tous les certificats.
import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
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.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
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.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class HttpsClientBuilder {
public static DefaultHttpClient getBelieverHttpsClient() {
DefaultHttpClient client = null;
SchemeRegistry Current_Scheme = new SchemeRegistry();
Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
try {
Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpParams Current_Params = new BasicHttpParams();
int timeoutConnection = 8000;
HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
client = new DefaultHttpClient(Current_Manager, Current_Params);
//HttpPost httpPost = new HttpPost(url);
//client.execute(httpPost);
return client;
}
public static class Naive_SSLSocketFactory extends SSLSocketFactory
{
protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");
public Naive_SSLSocketFactory ()
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException
{
super(null, null, null, null, null, (X509HostnameVerifier)null);
Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket();
}
}
private static class X509_Trust_Manager implements X509TrustManager
{
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
};
}
Je ne connais pas les spécificités d'Android pour les certificats SSL, mais il serait logique qu'Android n'accepte pas un certificat SSL auto-signé dès le départ. J'ai trouvé ce post sur les forums Android qui semble résoudre le même problème: http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
Il s'agit d'un problème connu avec Android 2.x. Je luttais avec ce problème pendant une semaine jusqu'à ce que je tombe sur la question suivante, qui non seulement donne un bon aperçu du problème, mais fournit également une solution fonctionnelle et efficace dépourvue de toute faille de sécurité.
Erreur `` Pas de certificat de pair '' dans Android 2.3 mais PAS dans 4
Pour une raison quelconque, la solution mentionnée pour httpClient ci-dessus n'a pas fonctionné pour moi. À la fin, j'ai pu le faire fonctionner en remplaçant correctement la méthode lors de l'implémentation de la classe SSLSocketFactory personnalisée.
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException, UnknownHostException
{
return sslFactory.createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslFactory.createSocket();
}
C'est ainsi que cela a parfaitement fonctionné pour moi. Vous pouvez voir la classe personnalisée complète et l'implémentation sur le fil suivant: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
Je fais ce cours et j'ai trouvé
package com.example.fakessl;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import android.util.Log;
public class CertificadoAceptar {
private static TrustManager[] trustManagers;
public static class _FakeX509TrustManager implements
javax.net.ssl.X509TrustManager {
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return (true);
}
public boolean isServerTrusted(X509Certificate[] chain) {
return (true);
}
public X509Certificate[] getAcceptedIssuers() {
return (_AcceptedIssuers);
}
}
public static void allowAllSSL() {
javax.net.ssl.HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
javax.net.ssl.SSLContext context = null;
if (trustManagers == null) {
trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
}
try {
context = javax.net.ssl.SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
Log.e("allowAllSSL", e.toString());
} catch (KeyManagementException e) {
Log.e("allowAllSSL", e.toString());
}
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
}
dans ton code blanc
CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
Sources qui m'ont aidé à travailler avec mon certificat auto-signé sur mon serveur AWS Apache et à me connecter avec HttpsURLConnection à partir d'un appareil Android:
SSL sur l'instance aws - tutoriel amazon sur ssl
Android Security avec HTTPS et SSL - création de votre propre gestionnaire de confiance sur le client pour l'acceptation votre certificat Création d' un certificat
auto-signé - script facile pour créer vos certificats
Ensuite, j'ai fait ce qui suit:
create_my_certs.sh
:#!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -key all/my-private-root-ca.privkey.pem \ -days 1024 \ -out all/my-private-root-ca.cert.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" # Create a Device Certificate for each domain, # such as example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use openssl genrsa \ -out all/privkey.pem \ 2048 # Create a request from your Device, which your Root CA will sign openssl req -new \ -key all/privkey.pem \ -out all/csr.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" # Sign the request from Device with your Root CA openssl x509 \ -req -in all/csr.pem \ -CA all/my-private-root-ca.cert.pem \ -CAkey all/my-private-root-ca.privkey.pem \ -CAcreateserial \ -out all/cert.pem \ -days 500 # Put things in their proper place rsync -a all/{privkey,cert}.pem server/ cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/
bash create_my_certs.sh yourdomain.com
Placez les certificats à leur place sur le serveur (vous pouvez trouver la configuration dans /etc/httpd/conf.d/ssl.conf). Tous ceux-ci doivent être définis:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Redémarrez httpd en utilisant sudo service httpd restart
et assurez-vous que httpd a démarré:
Arrêt de httpd: [OK]
Démarrage de httpd: [OK]
Copier my-private-root-ca.cert
dans le dossier des actifs de votre projet Android
Créez votre gestionnaire de confiance:
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("ma-racine-privée-ca.cert.pem"); Certificat ca; essayez {ca = cf.generateCertificate (caInput); } enfin {caInput.close (); }
// 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 = SSLContext.getInstance("TLS");
SSSLContext.init(null, tmf.getTrustManagers(), null);
Et établissez la connexion en utilisant HttpsURLConnection:
Connexion HttpsURLConnection = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
Thats it, essayez votre connexion https.
Utilisez simplement cette méthode comme HTTPClient:
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}