2013-04-30 8 views
11

TLSネゴシエーション中、クライアントはサポートされている暗号のリストをサーバーに送信し、サーバーはその暗号を選択して暗号化を開始します。 HttpsURLConnectionを通信に使用しているときに、この暗号リストをAndroidでサーバーに送信するように変更したいと考えています。HttpsURLConnectionを使用しているときにAndroidによってサーバーに送信された暗号化リストを上書きする方法は?

私は、setSSLSocketFactoryHttpsURLConnectionオブジェクトに使用して、SSLSocketFactoryを使用するように設定できることを知っています。これは、SSLSocketFactoryによって返されたSSLSocketによって使用されるtrustmanagerなどを変更したい場合に便利です。

この暗号リストは、SSLParametersオブジェクトを使って編集し、それをSSlsocketまたはSSLEngineオブジェクトに渡すことができます。

しかし、SSLSocketFactoryはこのような方法を公開していないようです。

私はHttpsURLConnectionに渡すSSLSocketFactoryによって作成された返さSSLSocketオブジェクトのSSLParametersを変更する方法を見つけることができません。

どうすればよいですか?

これはAndroidに限らず、一般的にJavaにも関係すると思います。 OOの方法があるかもしれません(例:SSLSocketFactoryを拡張してHttpsURLConnectionに提供してください)

答えて

13

このコードは少し生のものです。慎重に使用してください。

public class PreferredCipherSuiteSSLSocketFactory extends SSLSocketFactory { 


private static final String PREFERRED_CIPHER_SUITE = "TLS_RSA_WITH_AES_128_CBC_SHA"; 

private final SSLSocketFactory delegate; 

public PreferredCipherSuiteSSLSocketFactory(SSLSocketFactory delegate) { 

    this.delegate = delegate; 
} 

@Override 
public String[] getDefaultCipherSuites() { 

    return setupPreferredDefaultCipherSuites(this.delegate); 
} 

@Override 
public String[] getSupportedCipherSuites() { 

    return setupPreferredSupportedCipherSuites(this.delegate); 
} 

@Override 
public Socket createSocket(String arg0, int arg1) throws IOException, 
     UnknownHostException { 

    Socket socket = this.delegate.createSocket(arg0, arg1); 
    String[] cipherSuites = setupPreferredDefaultCipherSuites(delegate); 
    ((SSLSocket)socket).setEnabledCipherSuites(cipherSuites); 

    return socket; 
} 

@Override 
public Socket createSocket(InetAddress arg0, int arg1) throws IOException { 

    Socket socket = this.delegate.createSocket(arg0, arg1); 
    String[] cipherSuites = setupPreferredDefaultCipherSuites(delegate); 
    ((SSLSocket)socket).setEnabledCipherSuites(cipherSuites); 

    return socket; 
} 

@Override 
public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3) 
     throws IOException { 

    Socket socket = this.delegate.createSocket(arg0, arg1, arg2, arg3); 
    String[] cipherSuites = setupPreferredDefaultCipherSuites(delegate); 
    ((SSLSocket)socket).setEnabledCipherSuites(cipherSuites); 

    return socket; 
} 

@Override 
public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) 
     throws IOException, UnknownHostException { 

    Socket socket = this.delegate.createSocket(arg0, arg1, arg2, arg3); 
    String[] cipherSuites = setupPreferredDefaultCipherSuites(delegate); 
    ((SSLSocket)socket).setEnabledCipherSuites(cipherSuites); 

    return socket; 
} 

@Override 
public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, 
     int arg3) throws IOException { 

    Socket socket = this.delegate.createSocket(arg0, arg1, arg2, arg3); 
    String[] cipherSuites = setupPreferredDefaultCipherSuites(delegate); 
    ((SSLSocket)socket).setEnabledCipherSuites(cipherSuites); 

    return socket; 
} 

private static String[] setupPreferredDefaultCipherSuites(SSLSocketFactory sslSocketFactory) { 

    String[] defaultCipherSuites = sslSocketFactory.getDefaultCipherSuites(); 

    ArrayList<String> suitesList = new ArrayList<String>(Arrays.asList(defaultCipherSuites)); 
    suitesList.remove(PREFERRED_CIPHER_SUITE); 
    suitesList.add(0, PREFERRED_CIPHER_SUITE); 

    return suitesList.toArray(new String[suitesList.size()]); 
} 

private static String[] setupPreferredSupportedCipherSuites(SSLSocketFactory sslSocketFactory) { 

    String[] supportedCipherSuites = sslSocketFactory.getSupportedCipherSuites(); 

    ArrayList<String> suitesList = new ArrayList<String>(Arrays.asList(supportedCipherSuites)); 
    suitesList.remove(PREFERRED_CIPHER_SUITE); 
    suitesList.add(0, PREFERRED_CIPHER_SUITE); 

    return suitesList.toArray(new String[suitesList.size()]); 
} 
} 

使用したいとき。

  HttpsURLConnection connection = (HttpsURLConnection) (new URL(url)) 
       .openConnection(); 
     SSLContext context = SSLContext.getInstance("TLS"); 
     TrustManager tm[] = {new SSLPinningTrustManager()}; 
     context.init(null, tm, null); 
     SSLSocketFactory preferredCipherSuiteSSLSocketFactory = new PreferredCipherSuiteSSLSocketFactory(context.getSocketFactory()); 
     connection.setSSLSocketFactory(preferredCipherSuiteSSLSocketFactory); 
        connection.connect(); 

ありがとう。

+0

小精度:これはjavax.net.ssl.SSLSocketFactoryであり、SSLSocketFactoryではありません。 –

+1

ここにSSLPinningTrustManagerとは何ですか? "SSLPinningTrustManager"はユーザーが定義したクラスです(Android Studioは解決できません)。 – Amritesh

+0

@Amriteshおそらく 'SSLPinningTrustManager'は[this implementation](https://github.com/duladissa/SSLPinnigExample/blob/master/app/src/main/java/com/litedreamz/sslpinnigexample/util/SSLPinningTrustManager.java)を参照しています。 –

3

@ ThinkChrisの回答1で技術をバンドルし、単純なメソッド呼び出しにしました。 AndroidのHttpsURLConnectionを使用している場合は、NetCipherライブラリを使用して最新のTLS設定を取得できます。 NetCipherは、HttpsURLConnectionインスタンスが最高のサポートされているTLSバージョンを使用するように設定し、SSLv3サポートを削除し、そのTLSバージョンに対して最適な一連の暗号を設定します。

compile 'info.guardianproject.netcipher:netcipher:1.2' 

それとも、netcipher-1.2.jarをダウンロードし、アプリ内で直接それを含めることができます:まず、あなたのbuild.gradleに追加します。そして、代わりに呼び出す:

HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection(); 

コールこの:あなたは、特にその暗号リストをカスタマイズしたい場合は

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl); 

を、あなたはそこにコードをチェックすることができます。しかし、ほとんどの人は暗号リストについて考える必要はなく、代わりにデフォルトの共通ベストプラクティスを使用するべきです。

-1

このコードでは、予期せぬ不具合を修正しましたjavax.net.ssl.SSLHandshakeException

jdk1.8.0_92およびOracle JCEの無制限強度ポリシーファイルへのアップグレードは役に立たず、HttpsUrlConnectionに特定のSSLParametersを適用しようとして失敗しました。このウェブサイトの前について2016年4月15日までOK勤務した後、失敗し始め

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

:次のエラーでhttps://www.adrbnymellon.com結果を読み取るためにHttpsUrlConnectionを使用しようと特に

、。私は、ウェブサイトがDROWNの脆弱性のためにSSLv2HelloSSLv3のサポートを中止したことが原因だと考えています。素晴らしい分析については、thisを参照してください。

private static final String PREFERRED_CIPHER_SUITE = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; 
SSLContext context = SSLContext.getInstance("TLSv1.2"); 

私は、これは他の誰かの役に立てば幸い:ウェブサイトへ

のアクセスは、わずか2定数に変更して、コードを変更することで作業を始めました。

関連する問題