2013-05-05 19 views
5

Ich habe diese Methode:ändert HTTP-Post-Anfrage auf HTTPS Post Anfrage:

public static String getReportMetadata (String reportId, String sessionId, String url) throws Exception{ 

    Map<String, Object> jsonValues = new HashMap<String, Object>(); 
    jsonValues.put("reportID", reportId); 
    jsonValues.put("sessionID", sessionId); 
    JSONObject json = new JSONObject(jsonValues); 

    DefaultHttpClient client = new DefaultHttpClient(); 

    HttpPost post = new HttpPost(url + GET_REPORT_METADATA_ACTION); 

    AbstractHttpEntity entity = new ByteArrayEntity(json.toString().getBytes("UTF8")); 
    entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); 
    post.setEntity(entity);   
    HttpResponse response = client.execute(post); 

    return getContent(response);    
} 

, die ein HTTP Gesuch durchführt, die von-Kurs I AsyncTask laufe unter Verwendung von Daten von dem Server zu erhalten.

Meine Frage: könnte jemand mir bitte erklären, auf einfache Art und Weise, was die Schritte sind muss ich führen diese Verbindungsart auf eine sichere Verbindung zu ändern (a.k.a mit HTTPS). Nur von Android-Sicht (dh die Client-Anwendung).

UPDATE: Wie vorgeschlagen habe ich nur den Link zu ändern versucht und https statt http hinzufügen, aber es eine Antwort nicht zurück. Wie ich verstehe ich brauche, um ein Selbst Zeichen Zertifikat um

UPDATE2 auf Server-Seite zu verbinden zu erhalten und zu speichern: Die Lösung, die für mich funktioniert:

EasySSLSocketFactory:

public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory { 

private SSLContext sslcontext = null; 

private static SSLContext createEasySSLContext() throws IOException { 
    try { 
     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null); 
     return context; 
    } catch (Exception e) { 
     throw new IOException(e.getMessage()); 
    } 
} 

private SSLContext getSSLContext() throws IOException { 
    if (this.sslcontext == null) { 
     this.sslcontext = createEasySSLContext(); 
    } 
    return this.sslcontext; 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int, 
*  java.net.InetAddress, int, org.apache.http.params.HttpParams) 
*/ 
public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort, 
     HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { 
    int connTimeout = HttpConnectionParams.getConnectionTimeout(params); 
    int soTimeout = HttpConnectionParams.getSoTimeout(params); 
    InetSocketAddress remoteAddress = new InetSocketAddress(host, port); 
    SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); 

    if ((localAddress != null) || (localPort > 0)) { 
     // we need to bind explicitly 
     if (localPort < 0) { 
      localPort = 0; // indicates "any" 
     } 
     InetSocketAddress isa = new InetSocketAddress(localAddress, localPort); 
     sslsock.bind(isa); 
    } 

    sslsock.connect(remoteAddress, connTimeout); 
    sslsock.setSoTimeout(soTimeout); 
    return sslsock; 

} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#createSocket() 
*/ 
public Socket createSocket() throws IOException { 
    return getSSLContext().getSocketFactory().createSocket(); 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) 
*/ 
public boolean isSecure(Socket socket) throws IllegalArgumentException { 
    return true; 
} 

/** 
* @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int, 
*  boolean) 
*/ 
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, 
     UnknownHostException { 
    return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); 
} 

// ------------------------------------------------------------------- 
// javadoc in org.apache.http.conn.scheme.SocketFactory says : 
// Both Object.equals() and Object.hashCode() must be overridden 
// for the correct operation of some connection managers 
// ------------------------------------------------------------------- 

public boolean equals(Object obj) { 
    return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class)); 
} 

public int hashCode() { 
    return EasySSLSocketFactory.class.hashCode(); 
} 
} 

EasyX509TrustManager:

public class EasyX509TrustManager implements X509TrustManager { 

private X509TrustManager standardTrustManager = null; 

/** 
* Constructor for EasyX509TrustManager. 
*/ 
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException { 
    super(); 
    TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    factory.init(keystore); 
    TrustManager[] trustmanagers = factory.getTrustManagers(); 
    if (trustmanagers.length == 0) { 
     throw new NoSuchAlgorithmException("no trust manager found"); 
    } 
    this.standardTrustManager = (X509TrustManager) trustmanagers[0]; 
} 

/** 
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) 
*/ 
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException { 
    standardTrustManager.checkClientTrusted(certificates, authType); 
} 

/** 
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) 
*/ 
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException { 
    if ((certificates != null) && (certificates.length == 1)) { 
     certificates[0].checkValidity(); 
    } else { 
     standardTrustManager.checkServerTrusted(certificates, authType); 
    } 
} 

/** 
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() 
*/ 
public X509Certificate[] getAcceptedIssuers() { 
    return this.standardTrustManager.getAcceptedIssuers(); 
} 
} 

Und fügte ich diese Methode: getNewHttpClient()

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

schließlich für jeden Platz in meinem Code, die ich hatte:

DefaultHttpClient client = new DefaultHttpClient(); 

Ich ersetze es mit:

HttpClient client = getNewHttpClient(); 

Ich bin jetzt in der Lage, die Daten von der Serverseite zu erhalten, letzte Frage ist: Ist das, was ich getan habe, sicher? oder es akzeptiert jedes selbstsignierte Zertifikat? Wenn dies der Fall ist, was sollte getan werden, um es zu ändern?

Jede Hilfe wäre willkommen.

+0

Vielleicht hilft Ihnen Javadoc: [SchemeRegistry] (http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/scheme/SchemeRegistry.html) [SSLSocketFactory] (http: //hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ssl/SSLSocketFactory.html) – mleczey

+1

Gemäß [HTTPClient SSL Guide] (htt p: //hc.apache.org/httpclient-legacy/sslguide.html), das einzige, was Sie tun müssen, ist "https: //" in Ihre URL-Zeichenfolge einzugeben. Dadurch erhalten Sie eine HTTPS-Verbindung mit einer Browser-äquivalenten Authentifizierungsebene (d. H. Eine beliebige von mehreren hundert Zertifizierungsstellen kann das Serverzertifikat signieren). Die 'SchemeRegistry' und' SSLSocketFactory' spielen nur dann eine Rolle, wenn Sie die SSL-Behandlung anpassen möchten, typischerweise um SSL-Pinning zu implementieren (dh eine stärkere Authentizitätsbeschränkung verwenden). Schauen Sie sich Moxies Github für einen guten (LGPL lizensierten) Android ssl pinner an. – Barend

+0

@Barend, ich habe versucht, nur den Link zu ändern und https anstelle von http hinzufügen, aber es gibt keine Antwort zurück. Soweit ich weiß, muss ich ein Self-Sign-Zertifikat beschaffen und speichern, um eine Verbindung zur Serverseite herzustellen. –

Antwort

5

Von der Apache HttpClient SSL guide:

sichere HTTP-Kommunikation über SSL sollte so einfach wie einfache HTTP-Kommunikation sein.// XXXX https: // XXXX

EDIT:

So sollten Sie einfach die http ändern Ich habe gerade @Barend ‚s Antwort gesehen, die vollständiger ist

+0

Ich habe versucht, nur den Link zu ändern und https anstelle von http hinzufügen, aber es gibt keine Antwort zurück. Wie ich es verstehe, muss ich ein Self-Sign-Zertifikat erhalten, um eine Verbindung zur Serverseite herzustellen. –

+0

Wenn der Server über ein selbstsigniertes Zertifikat verfügt, müssen Sie Ihrem HttpClient mitteilen, dass er das Zertifikat akzeptieren soll. Wenn Sie dies tun möchten, können Sie hier http://stackoverflow.com/questions/1217141/self-signed-ssl-acceptance-android suchen – user2340612

5

Zunächst einmal müssen Sie SchemeRegistry Objekt und registrieren neues Schema mit SSLSocketFactory erstellen:

SchemeRegistry schemeRegistry = new SchemeRegistry(); 
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 

Dann erstellen Sie können Ihre SingleClientConnManager mit SchemeRegistry Objekt:

SingleClientConnManager mgr = new SingleClientConnManager(schemeRegistry); 

Und schließlich erstellen Sie Ihre DefaultHttpClient mit SingleClientConnManager:

HttpClient client = new DefaultHttpClient(mgr); 
+0

Würde es Ihnen etwas ausmachen, ein wenig mehr auf dieses Objekt zu erarbeiten? soll ich die beschriebenen Schritte vor jedem Zugriff auf den https Web Service durchführen? Wie ich es verstehe, sollte ich ein Zertifikat vom Server erhalten und es auf dem Gerät speichern, habe ich recht? –

+0

@EmilAdz Ja, Sie sollten diese Schritte vor jedem https-Zugriff durchführen. 'SchemeRegistry' ist nur ein Container für alle 'Scheme'-Objekte, der HTTPS-Verbindungsparameter beschreibt, so dass Sie für alle Ihre Aufrufe eine Instanz des' SchemeRegisty'-Objekts verwenden können. Sie benötigen jedoch für jeden Anruf einen neuen 'SingleClientConnManager', da dieser nur jeweils eine Verbindung verwalten kann. Ich denke, das Speichern von SSL-Zertifikaten wird von Android selbst bereitgestellt, sodass Sie sich keine Sorgen machen müssen. – nemezis