SSL - /TLS-Protokolle und cipher-suites mit dem AndroidHttpClient

EDIT: Entschuldigt, wenn meine ursprüngliche post war schlecht formuliert. Dies führte zu einiger Verwirrung, vertreten durch Kommentare auf den ursprünglichen Beitrag. Also lassen Sie es mich noch einmal versuchen:

Begann ich mit einer Frage. Ich wollte ein problem lösen, auf Android, wusste aber nicht wie. Ich verbrachte viel Zeit mit der Suche im Netz nach Lösungen, fand aber keine einzige Diskussion der Angelegenheit überall. Dennoch, eine Reihe von Diskussionen, einschließlich der StackOverflow-threads, führte mich zu einer Technik, die sah vielversprechend aus. Ich habe das problem gelöst. Aber die Lösung war ein wenig beteiligt. Also beschloss ich, poste die Frage hier, denken a) es muss eine bessere Lösung, und hoffentlich wird jemand wissen, und poste das hier genau richtig; oder b) vielleicht ist dies eine gute Lösung, und da ich keine Diskussion über die Angelegenheit überall sonst im Netz, vielleicht meine Lösung für das problem wäre es hilfreich zu anderen, die versuchen, das gleiche zu tun. So oder so, das Ergebnis wäre ein neuer Beitrag in StackOverflow: eine Frage, die nicht beantwortet anderswo, mit, irgendwann ist die richtige Antwort auf die eine oder andere Weise. In der Tat, StackOverflow auch mich eingeladen, um Antwort auf meine eigene Frage durch mein wissen teilen, wenn ich Zitat es. Das war in der Tat ein Teil meiner motivation. Auch die Fakten zu dieser Angelegenheit sind nicht überall gesammelt, die ich gefunden habe.

Also:

F: Bei Verwendung der AndroidHttpClient, um REST-Anfragen über HTTPS, wie kann ich festlegen, welche SSL-Protokolle und Chiffren zu verwenden?

Dies ist wichtig. Der Punkt ist gut getroffen, dass es vieles gibt, das getan werden kann, auf dem server, aber es gibt Grenzen. Dem gleichen server zu dienen hat-Browsern, einschließlich der alten, als auch mit anderen Kunden. Das bedeutet, dass der server die Unterstützung für eine Breite Palette von Protokollen und Verschlüsselungen. Auch innerhalb von Android, wenn Sie zur Unterstützung eine Menge von verschiedenen Versionen, die Sie gehen zu müssen, um die Unterstützung einer Reihe verschiedener Protokolle und Chiffren.

Wichtiger ist, standardmäßig OpenSSL Auszeichnung die Kunden-Chiffre Präferenz nicht server, während des SSL-Handshakes. Sehen Sie diese post, zum Beispiel, das sagt, dass Sie können dieses Verhalten überschreiben, in der der AUFTRAGGEBER durch die Einstellung SSL_OP_CIPHER_SERVER_PREFERENCE. Es ist nicht ganz klar, ob diese option kann auch festgelegt werden, auf ein SSLSocket in Java. Selbst wenn es kann, können Sie die cipher-Liste selbst oder dem client mitzuteilen, zu Ehren der server-Liste. Sonst, Sie sind immer die Android-Standard, was immer es sein mag für die version, die Sie laufen (nicht die version, die Sie Links vor).

Wenn Sie die Standardeinstellungen übernehmen, der Präferenz-Liste, die vom client gesendet, um den server von einem Jellybean 4.2+ client gesehen werden kann hier, beginnend in Zeile 504. Die default-Liste der Protokolle beginnt um die Linie 620. Obwohl Jellybean 4.2+ beinhaltet die Unterstützung für OpenSSL-1.0.1, besonders TLSv1.1 und TLSv1.2, die Protokolle sind nicht standardmäßig aktiviert. Wenn Sie nicht etwas tun wie das, was ich getan habe, Sie können nicht nutzen TLSv1.2 Unterstützung, trotz der Tatsache, dass die Unterstützung für TLSv1.2 ist angekündigt, die auf den jüngsten Versionen von Android. Und die details unterscheiden sich durchaus ein wenig als Sie zurück durch die vorherigen Android-Versionen. Zumindest, möchten Sie vielleicht werfen Sie einen Blick auf die standardmäßig auf allen unterstützten Versionen und sehen, was Ihre Kunden tatsächlich tun. Sie werden überrascht sein.

Es gibt viel mehr können Sie sagen, über die Unterstützung für verschiedene Protokolle und Chiffren. Der Punkt ist, es kann manchmal notwendig sein, ändern Sie diese Einstellungen in einem client.

A. Verwenden Sie eine benutzerdefinierte SSLSocketFactory

Dies funktionierte gut für mich, und am Ende, es war nicht sehr viel code. Aber es war ein wenig dornig für eine Reihe von Gründen:

  • Es gibt zwei verschiedene SSLSocketFactory-Klassen. Der client benötigt eine
    org.apache.http.conn.ssl.SSLSocketFactory, aber OpenSSL gibt eine
    javax.net.ssl.SSLSocketFactory. Das ist definitiv verwirrend. Ich verwendet
    delegation zu machen, die ein Anruf der anderen, ohne viel problem.
  • Watch out für die Differenz zwischen den OpenSSLContextImpl und die
    SSLContextImpl. Gerade umschließt die anderen, aber Sie sind nicht
    austauschbar. Wenn ich
    SSLContextImpl.engineGetSocketFactory Methode—ich vergessen, was genau
    passiert ist, aber etwas leise ausgefallen. Verwenden Sie unbedingt ein
    OpenSSLContextImpl, um Ihre socket-Fabrik, nicht eine SSLContextImpl.
    Sie könnten auch in der Lage sein zu verwenden
    javax.net.ssl.SSLSocketFactory.getDefault(), aber ich bin mir nicht sicher.
  • Kann man nicht einfach eine Unterklasse AndroidHttpClient, denn Ihr Konstruktor ist
    private. Dies ist bedauerlich, da es bietet einige andere nette
    goodies, wie machen Sie sicher, dass Sie ihn Herunterfahren ordnungsgemäß statt
    undichte Ressourcen. Die DefaultHttpClient funktioniert Prima. Ich lieh mir
    der newInstance-Methode von AndroidHttpClient (um die Zeile 105).

Die wichtigsten Punkte:

public class SecureSocketFactory extends SSLSocketFactory {
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        //order should not matter here; the server should select the highest
        //one from this list that it supports
        s.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1" });

        //order matters here; specify in preference order
        s.setEnabledCipherSuites(new String[] { "ECDHE-RSA-RC4-SHA", "RC4-SHA" });

Dann:

//when creating client
HttpParams params;
SchemeRegistry schemeRegistry = new SchemeRegistry();

//use custom socket factory for https
SSLSocketFactory sf = new SecureSocketFactory();
schemeRegistry.register(new Scheme("https", sf, 443));

//use the default for http
schemeRegistry.register(new Scheme("http",
            PlainSocketFactory.getSocketFactory(), 80));

ClientConnectionManager manager =
            new ThreadSafeClientConnManager(params, schemeRegistry);

HttpClient client = new DefaultHttpClient(manager, params);

Unter Android 3.0 (Honeycomb/SDK 11), die unterstützten cipher-Optionen werden mehr begrenzt, und es gibt weniger motivation um die Standardwerte zu überschreiben. Auf FROYO/SDK 8, meine SecureSocketFactory bläst für einige Grund, und die jury ist sich am 10. Aber es scheint zu funktionieren für 11 aufwärts in Ordnung.

Die vollständige Lösung ist in einem öffentlichen github repo.

Andere Lösung wäre die Verwendung einer HttpsUrlConnection, die macht es einfach, um eine benutzerdefinierte socket-Fabrik, aber ich glaube, Sie werden wahrscheinlich verlieren noch mehr die Bequemlichkeit des high-level-HTTP-client. Ich habe keine Erfahrung mit HttpsUrlConnection.

  • Stackoverflow ist nicht wirklich für Diskussionen, siehe dieses Zitat aus der Hilfe Seite: If your motivation for asking the question is “I would like to participate in a discussion about ______”, then you should not be asking here. Unter "Welche Arten von Fragen sollte ich vermeiden, dass zu Fragen?" §
  • Die motivation für die Frage ist, zu lernen, die richtige Antwort. Sorry wenn du das falsch verstanden, die.
  • Ich kann sicherlich nicht behaupten, zu wissen, was Ihre motivation war. aber das "but I think StackOverflow is a better place for this discussion." sicher macht es scheinen, wie Sie sind, nach einer Diskussion. Durch die Definitionen aufgelistet, auf die Hilfe Seite ist dein Beitrag off-topic SO. Ich kann verstehen, dass eine Diskussion Wert, aber wie es jetzt steht, das ist wirklich nicht der geeignete Ort dafür.
  • Frage ist sicher off-topic, aber hast du den server rechts, die Sie nicht haben, etwas zu tun auf dem client.
  • EJP - warum würden Sie denken, der server ist korrekt konfiguriert? Ich kann Ihnen nicht sagen, wie viele Male habe ich gehört ", Folgen wir best practices" und dann finden Sie heraus, dass Sie nicht die Unterstützung von secure Nachverhandlung, keine Unterstützung für TLS 1.2 verwenden Sie eine 512-bit-Schlüssel, anonyme Protokolle, verwenden Sie den export-Grad-Verschlüsselungen, etc. Ubuntu 12.024 LTS ist ein leuchtendes Beispiel - nicht TLS 1.2, weil seine Verwendung von OpenSSL 1.0.0 (und so viel für die long term support). openssl s_client und wireshark sind tattle tales 🙂
InformationsquelleAutor Jimmy Dee | 2013-08-30
Schreibe einen Kommentar