Ich mache einen https-Beitrag und erhalte eine Ausnahme von der SSL-Ausnahme. Nicht vertrauenswürdiges Serverzertifikat. Wenn ich normales http mache, funktioniert es einwandfrei. Muss ich das Serverzertifikat irgendwie akzeptieren?
Ich mache einen https-Beitrag und erhalte eine Ausnahme von der SSL-Ausnahme. Nicht vertrauenswürdiges Serverzertifikat. Wenn ich normales http mache, funktioniert es einwandfrei. Muss ich das Serverzertifikat irgendwie akzeptieren?
Antworten:
Ich vermute, aber wenn Sie möchten, dass ein tatsächlicher Handschlag stattfindet, müssen Sie Android über Ihr Zertifikat informieren. Wenn Sie einfach akzeptieren möchten, egal was passiert, verwenden Sie diesen Pseudocode, um das zu erhalten, was Sie mit dem Apache HTTP-Client benötigen:
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 ist eine Klasse, die implementiert javax.net.ssl.X509TrustManager, doch keines der Verfahren tatsächlich keine Arbeit ausführen, um eine Probe erhalten hier .
Viel Glück!
FullX509TrustManager
Das mache ich. Das Zertifikat wird einfach nicht mehr überprüft.
// 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();
}
}
und
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. Ich habe auch versucht , Ersatz TLSmit , SSLaber es hat nicht geholfen. Bitte helfen Sie mir, danke
Beim Versuch, diese Frage zu beantworten, habe ich ein besseres Tutorial gefunden. Damit müssen Sie die Zertifikatsprüfung nicht gefährden.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* Ich habe das nicht geschrieben, aber danke an Bob Lee für die Arbeit
Sie können sich auch meinen Blog-Artikel ansehen, der den Crazybobs sehr ähnlich ist.
Diese Lösung beeinträchtigt auch nicht die Zertifikatsprüfung und erklärt, wie Sie die vertrauenswürdigen Zertifikate in Ihrem eigenen Schlüsselspeicher hinzufügen.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
Mit freundlicher Genehmigung von Maduranga
Bei der Entwicklung einer Anwendung, die https verwendet, verfügt Ihr Testserver nicht über ein gültiges SSL-Zertifikat. Oder manchmal verwendet die Website ein selbstsigniertes Zertifikat oder die Website verwendet ein kostenloses SSL-Zertifikat. Wenn Sie also versuchen, mit Apache HttpClienteine Verbindung zum Server herzustellen , wird eine Ausnahme angezeigt, die besagt, dass der Peer nicht authentifiziert ist. Obwohl es nicht empfehlenswert ist, allen Zertifikaten einer Produktionssoftware zu vertrauen, müssen Sie dies möglicherweise je nach Situation tun. Diese Lösung behebt die Ausnahme, die durch "Peer nicht authentifiziert" verursacht wird.
Bevor wir jedoch zur Lösung gehen, muss ich Sie warnen, dass dies keine gute Idee für eine Produktionsanwendung ist. Dies verstößt gegen den Zweck der Verwendung eines Sicherheitszertifikats. Verwenden Sie diese Lösung nicht, es sei denn, Sie haben einen guten Grund oder sind sich sicher, dass dies keine Probleme verursacht.
Normalerweise erstellen Sie eine HttpClientsolche.
HttpClient httpclient = new DefaultHttpClient();
Sie müssen jedoch die Art und Weise ändern, wie Sie den HttpClient erstellen.
Zuerst müssen Sie eine Klassenerweiterung erstellen 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();
}
}
Erstellen Sie dann eine Methode wie diese.
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();
}
}
Dann können Sie die erstellen HttpClient.
HttpClient httpclient = getNewHttpClient();
Wenn Sie versuchen, eine Post-Anfrage an eine Anmeldeseite zu senden, sieht der Rest des Codes folgendermaßen aus.
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();
}
Sie erhalten die HTML-Seite zum InputStream. Dann können Sie mit der zurückgegebenen HTML-Seite tun, was Sie wollen.
Aber hier werden Sie vor einem Problem stehen. Wenn Sie eine Sitzung mithilfe von Cookies verwalten möchten, können Sie dies mit dieser Methode nicht tun. Wenn Sie die Cookies erhalten möchten, müssen Sie dies über einen Browser tun. Dann erhalten nur Sie Cookies.
Wenn Sie ein StartSSL- oder Thawte-Zertifikat verwenden, schlägt dies für Froyo und ältere Versionen fehl. Sie können das CAcert-Repository einer neueren Version verwenden, anstatt jedem Zertifikat zu vertrauen.
Keines davon hat bei mir funktioniert (was auch durch den Thawte-Bug noch verstärkt wurde ). Schließlich habe ich es mit selbstsignierter SSL-Akzeptanz unter Android behoben und die benutzerdefinierte SSL-Verarbeitung funktionierte unter Android 2.2 FroYo nicht mehr
Jede dieser Antworten hat bei mir nicht funktioniert. Hier ist ein Code, der Zertifikaten vertraut.
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;
}
};
}
Ich weiß nichts über die Android-Besonderheiten für SSL-Zertifikate, aber es wäre sinnvoll, dass Android ein selbstsigniertes SSL-Zertifikat nicht sofort akzeptiert. Ich habe diesen Beitrag in Android-Foren gefunden, der anscheinend dasselbe Problem behebt : http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
Dies ist ein bekanntes Problem mit Android 2.x. Ich hatte eine Woche lang mit diesem Problem zu kämpfen, bis ich auf die folgende Frage stieß, die nicht nur einen guten Hintergrund des Problems liefert, sondern auch eine funktionierende und effektive Lösung ohne Sicherheitslücken bietet.
Fehler 'Kein Peer-Zertifikat' in Android 2.3, aber NICHT in 4
Aus irgendeinem Grund hat die oben für httpClient erwähnte Lösung bei mir nicht funktioniert. Am Ende konnte ich es zum Laufen bringen, indem ich die Methode bei der Implementierung der benutzerdefinierten SSLSocketFactory-Klasse korrekt überschrieb.
@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();
}
So hat es bei mir perfekt funktioniert. Sie können die vollständige benutzerdefinierte Klasse und Implementierung im folgenden Thread sehen: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
Ich mache diese Klasse und gefunden
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());
}
}
in dir Code weiß das
CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
Quellen, die mir geholfen haben, mit meinem selbstsignierten Zertifikat auf meinem AWS Apache-Server zu arbeiten und eine Verbindung mit HttpsURLConnection vom Android-Gerät herzustellen:
SSL auf einer aws-Instanz - Amazon-Tutorial zu SSL
Android Security mit HTTPS und SSL - Erstellen eines eigenen Vertrauensmanagers auf dem Client zum Akzeptieren Ihr Zertifikat
Selbstsigniertes Zertifikat erstellen - einfaches Skript zum Erstellen Ihrer Zertifikate
Dann habe ich folgendes gemacht:
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.comPlatzieren Sie die Zertifikate an der richtigen Stelle auf dem Server (die Konfiguration finden Sie unter /etc/httpd/conf.d/ssl.conf). All dies sollte festgelegt werden:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Starten Sie httpd mit neu sudo service httpd restartund stellen Sie sicher, dass httpd gestartet wurde:
Stoppen von httpd: [OK]
Starten von httpd: [OK]
Kopieren Sie my-private-root-ca.certin Ihren Android-Projekt-Assets-Ordner
Erstellen Sie Ihren Vertrauensmanager:
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("my-private-root-ca.cert.pem"); Zertifikat ca; try {ca = cf.generateCertificate (caInput); } finally {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);Und stellen Sie die Verbindung mit HttpsURLConnection her:
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
Versuchen Sie es mit Ihrer https-Verbindung.
Verwenden Sie einfach diese Methode als 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();
}
}