2013-08-30 7 views
8

EDIT:オリジナルの投稿が不適切であると謝罪します。それは元の投稿へのコメントによって表されるいくつかの混乱につながった。だからもう一度試してみましょう:AndroidHttpClientを使用したSSL/TLSプロトコルと暗号スイート

私は質問から始めました。私はAndroidで問題を解決したかったのですが、どうしたらいいかわかりませんでした。私は解決のためにネットの周りを見回すのに多くの時間を費やしましたが、どこでも問題の議論は一件も見つかりませんでした。それにもかかわらず、StackOverflowスレッドを含む多くの議論が私に有望な技術につながった。私はこの問題を解決しました。しかし、その解決策は少し関わっていました。だから私はここに質問を掲示することにしました、a)より良い解決策が必要であり、誰かがここで回答者を知っていることを願っています。またはb)おそらくこれは良い解決策であり、ネット上のどこにでもその問題について議論していないので、問題に対する私の解決策は、同じことをしようとする他の人には役に立ちます。いずれにしても、結果はStackOverflowへの新たな貢献となるでしょう。つまり、どこか別の場所で回答されない質問、最終的に正しい答えの一方または両方です。実際、StackOverflowは、もともと私がそれを投稿したときに私の知識を共有する方法で私自身の質問に答えるように私を招待しました。それは実際に私のモチベーションの一部でした。この事実の事実さえ私が見つけたどこにも集められません。

ので:

Q. HTTPS経由でRESTリクエストを作るためにAndroidHttpClientを使用して、どのように私はSSLプロトコルと暗号を使うかを指定することができますか?

これは重要です。重要なのは、サーバー上でできることが多いということですが、制限があります。同じサーバーでは、古いものや他のクライアントを含むブラウザーにサービスを提供する必要があります。つまり、サーバーは広範なプロトコルと暗号をサポートする必要があります。 Android内でも、さまざまなバージョンをサポートする必要がある場合は、さまざまなプロトコルや暗号をサポートする必要があります。

デフォルトでは、OpenSSLはSSLハンドシェイク中にサーバのではなく、であるクライアントの暗号設定を優先します。たとえば、postを参照してください。これは、SSL_OP_CIPHER_SERVER_PREFERENCEを設定して、クライアントでその動作を上書きできることを示しています。このオプションがJavaのSSLSocketで設定できるかどうかは完全にはっきりしていません。可能であれば、暗号リストを自分で設定するか、クライアントにサーバーのリストを尊重するように指示することができます。それ以外の場合は、あなたが実行しているバージョン(リンクしているバージョンではありません)に関係なく、Androidのデフォルトを取得しています。

デフォルトを使用すると、Jellybean 4.2以降のクライアントによってクライアントからサーバーに送信されるプリファレンス・リストは、行番号504で始まるhereと表示されます。デフォルトのプロトコル・リストは620行目から始まります。Jellybean 4.2+ OpenSSL 1.0.1、特にTLSv1.1とTLSv1.2をサポートしていますが、これらのプロトコルはデフォルトでは有効になっていません。私がやったようなことをしなければ、TLSv1.2のサポートはAndroidの最近のバージョンで宣伝されているにもかかわらず、TLSv2.2のサポートを利用することはできません。以前のAndroidバージョンに戻っていくと、詳細はかなり変わります。少なくとも、サポートされているすべてのバージョンのデフォルトをよく見て、クライアントが実際に行っていることを確認してください。あなたは驚くかもしれません。

さまざまなプロトコルと暗号のサポートについてもっと多くのことが言えます。要点は、クライアントでこれらの設定を変更する必要があることがあります。

A.カスタムのSSLSocketFactoryを使用し

これは私のためによく働いた、そして最後に、それは非常に多くのコードではなかったです。しかし、いくつかの理由から少し難解でした。

  • 2つの異なるSSLSocketFactoryクラスがあります。クライアントには org.apache.http.conn.ssl.SSLSocketFactoryが必要ですが、OpenSSLは javax.net.ssl.SSLSocketFactoryを返します。これは間違いなく紛らわしいものです。私は 代表団を使用して、1つの電話を他の電話にかけても大した問題はありません。
  • OpenSSLContextImplと SSLContextImplの違いに注意してください。 1つはちょうど他を包みますが、彼らは を入れ替えることはできません。 SSLContextImpl.engineGetSocketFactoryメソッドを使用したときに、正確には の内容が忘れられましたが、何かが静かに失敗しました。 SSLContextImplではなく、 OpenSSLContextImplを使用してソケットファクトリを取得してください。 javax.net.ssl.SSLSocketFactory.getDefault()を使用することもできますが、わかりません。
  • AndroidHttpClientのサブクラスは、コンストラクタが プライベートなので簡単にサブクラス化できません。 リソースが漏れているのではなく、正常にシャットダウンされていることを確認するなど、他のnice グッズを提供しているので、残念です。 DefaultHttpClientは正常に動作します。 AndroidHttpClientのnewInstanceメソッドを (105行目)から借りました。

キーポイント:次に

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

:アンドロイド3.0(ハニカム/ SDK 11)以下

// 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); 

は、サポートされている暗号の選択肢は、より限定されたになり、あまりやる気がオーバーライドすることがありますデフォルト。 FROYO/SDK 8では、私のSecureSocketFactoryが何らかの理由で爆発し、陪審員は10歳になっています。

完全な解決策は公開されているgithub repoです。

もう1つの解決策は、カスタムソケットファクトリの使用を簡単にするHttpsUrlConnectionを使用することですが、おそらく上位レベルのHTTPクライアントの利便性を失うことになると思います。私はHttpsUrlConnectionの経験がありません。

+1

Stackoverflowは実際に議論するためのものではありません。[ヘルプセンターページ](http://stackoverflow.com/help)のこの引用符を参照してください: 'あなたの質問を求めるあなたの動機が「私は参加したい___についての議論では、ここで尋ねるべきではありません。」「どのような種類の質問を避けるべきですか?」セクション – FoamyGuy

+1

質問をする動機は、正しい答えを学ぶことです。申し訳ありませんが、あなたがそれを誤解した場合。 –

+1

私は確かにあなたのモチベーションが何だったかを主張することはできません。しかしこれは ""しかし、私はStackOverflowがこの議論のためのより良い場所だと思っています。 "[ヘルプページ](http://stackoverflow.com/help/dont-ask)にリストアップされている定義により、あなたの投稿はSOのトピック外です。私はそれが価値のある議論であることを理解することができますが、現時点ではこれは本当にそれが起こるのに適切な場所ではありません。 – FoamyGuy

答えて

1

AndroidHttpClientを使用してHTTPS経由でRESTリクエストを行う場合、どのSSLプロトコルと暗号を使用するかを指定するにはどうすればよいですか?

私はあなたがAndroidHttpClientとそれをすることができるとは思わない。 SSLSocketFactoryでもX509TrustManagerでも、私はチャネルを強化するために(暗号リスト、証明書のピン割り当て、公開鍵のピン割り当てなど)すべてカスタムクラスを必要としていました。それはJavaだし、Androidだ。 How to override the cipherlist sent to the server by Android when using HttpsURLConnection?を参照してください。

+0

あなたは正しいです、noloader。しかし、私は間違いなく混乱していました。 EJPは、独自のプリファレンスを使用するようにサーバーを設定すると、クライアントによって指定された順序は重要ではないという点で正しいです。これはopensslクライアントまたはサーバのデフォルトではありませんが、一般的な方法です。それが私の問題のほとんどを解決しました。 しかし、私が学んだ主なものは、あなたがAndroid 4.1以上でOpenSSL 1.0.1を(そしてTLSv1.1以上をサポートして)デフォルトでは入手できないことです。 AndroidHttpClientを使用している場合 –

+0

Jimmy - 「AndroidHttpClientを使用している場合、OpenSSL 1.0.1を取得しません」。うん、Androidは完全に骨抜きだ。彼らはOpenSSLの下位バージョンを使用しています(0.9.8、私は思います)。さらに、彼らは暗号リストを不正にしました( 'RC4-MD5'、私は信じています)。それはAndroid 2.3以降でボークされています。例えば、[なぜAndroid SSLがAES256-SHAからRC4-MD5にダウングレードされたのか(2010年後半)](http://op-co.de/blog/posts/android_ssl_downgrade/)を参照してください。 – jww

+0

ジミー - あなたの 'RC4-SHA'の選択に関して:しないでください。 Bernstein、AlFardanらは、TLSにおいてどのように壊れた 'RC4 'が存在するかを示した。 RonやRSAが何もできないことはありません。加えて、 'RC4'(悪のうち小さいもの)の使用を引き起こしたBEAST攻撃(2011年のパッディング攻撃)が修正されました。 IETFには、彼らの集団がそれぞれの尻を持ちます。たとえば、[TLSとWPAのRC4のセキュリティについて](http://cr.yp.to/streamciphers/rc4biases-20130708.pdf)を参照してください。 – jww

関連する問題