2013-04-30 4 views
11

TLS 협상 중에 클라이언트는 지원되는 암호 목록을 서버에 보내고 서버는이를 선택하고 암호화가 시작됩니다. 통신용으로 HttpsURLConnection을 사용할 때 안드로이드에 의해 서버로 전송 된 암호 목록을 변경하고 싶습니다.HttpsURLConnection을 사용할 때 Android에서 서버로 보낸 암호문을 재정의하는 방법은 무엇입니까?

나는 SSLSocketFactory을 사용하도록 HttpsURLConnection 개체에서 setSSLSocketFactory을 사용할 수 있음을 알고 있습니다. 이것은 SSLSocketFactory에 의해 반환 된 SSLSocket에 의해 사용되는 trustmanager 등을 변경하고자 할 때 유용합니다.

일반적으로이 암호 목록은 SSLParameters 개체를 사용하여 개체를 편집하고 제공된 메서드를 사용하여 SSlsocket 또는 SSLEngine 개체로 전달할 수 있음을 알고 있습니다.

그러나 SSLSocketFactory은 그런 방법을 드러내지 않습니다!

나는 HttpsURLConnection에 전달하는 SSLSocketFactory에 의해 생성 된 반환 SSLSocket 개체의 SSLParameters를 변경하는 방법을 찾을 수 없습니다.

어떻게해야합니까?

이것은 Android와 관련된 일반적인 자바와도 관련이 있습니다. 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에 적용하려고 시도했지만 실패했습니다. 다음과 같은 오류가 https://www.adrbnymellon.com 결과를 읽을 HttpsUrlConnection를 사용하기 특히

는 :

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

이 웹 사이트는 이전에 대한 2016년 4월 15일에 확인을 한 후, 실패 시작했다. 웹 사이트가 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 상수로 변경하는 코드를 수정하여 작업을 시작했다.