-->

如何覆盖使用HttpsURLConnection的时候发送到由Android服务器cipherlis

2019-09-01 12:00发布

在TLS协商,客户端发送支持的密码列表,到服务器,服务器挑选一个和加密开始。 我想改变这种cipherlist由Android发送到服务器,当我使用HttpsURLConnection通信。

我知道,我可以使用setSSLSocketFactoryHttpsURLConnection对象将其设置为使用SSLSocketFactory 。 当我想改变由使用的TrustManager等,这是有用SSLSocket通过返回SSLSocketFactory

我知道一般这个密码组列表可以使用编辑SSLParameters对象,并将其传递给SSlsocketSSLEngine使用他们提供的方法的对象。

SSLSocketFactory似乎并没有揭露这种方法!

我无法找到一个方法来改变SSLParameters返回的SSLSocket被创建的对象SSLSocketFactory我传递给HttpsURLConnection

该怎么办?

我想这也关系到Java在一般情况下,不仅是Android系统。 也许有一个面向对象的方式做到这一点(如延长SSLSocketFactory ,并提供到HttpsURLConnection ?)

Answer 1:

这段代码是一个比特原始。 请小心使用。

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

谢谢。



Answer 2:

我捆绑@ ThinkChris的答案技术1成死的简单方法调用。 您可以使用NetCipher库使用Android的时候得到一个现代TLS配置HttpsURLConnection 。 NetCipher配置HttpsURLConnection实例,用最好的支持TLS版本,删除SSLv3的支持,并配置密码为TLS版本的最好的套件。 首先,它添加到您的build.gradle:

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

或者你也可以下载netcipher-1.2.jar,并直接将其包含在您的应用程序。 然后,而不是调用的:

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

调用此:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);

如果您想特别定制密码列表,你可以有检查代码。 但大多数人不应该去想的密码列表,而不是它应该是默认使用普通的最佳实践。



Answer 3:

此代码奇效意料不到的javax.net.ssl.SSLHandshakeException

升级到jdk1.8.0_92和Oracle JCE无限制强度的政策文件并没有帮助,我是不成功的尝试特定应用SSLParametersHttpsUrlConnection

特别是,在尝试使用HttpsUrlConnection阅读https://www.adrbnymellon.com以下错误的结果:

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

本网站之前,大约2016年4月15日工作确定,然后开始失败。 我相信失败是由于该网站停止支持造成SSLv2HelloSSLv3由于淹死漏洞。 见这一个伟大的分析。

访问网站开始通过修改与变化,只是2常量的代码工作:

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

我希望这可以帮助别人。



文章来源: How to override the cipherlist sent to the server by Android when using HttpsURLConnection?