在TLS协商,客户端发送支持的密码列表,到服务器,服务器挑选一个和加密开始。 我想改变这种cipherlist由Android发送到服务器,当我使用HttpsURLConnection
通信。
我知道,我可以使用setSSLSocketFactory
上HttpsURLConnection
对象将其设置为使用SSLSocketFactory
。 当我想改变由使用的TrustManager等,这是有用SSLSocket
通过返回SSLSocketFactory
。
我知道一般这个密码组列表可以使用编辑SSLParameters
对象,并将其传递给SSlsocket
或SSLEngine
使用他们提供的方法的对象。
但SSLSocketFactory
似乎并没有揭露这种方法!
我无法找到一个方法来改变SSLParameters
返回的SSLSocket
被创建的对象SSLSocketFactory
我传递给HttpsURLConnection
。
该怎么办?
我想这也关系到Java在一般情况下,不仅是Android系统。 也许有一个面向对象的方式做到这一点(如延长SSLSocketFactory
,并提供到HttpsURLConnection
?)
这段代码是一个比特原始。 请小心使用。
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();
谢谢。
我捆绑@ 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);
如果您想特别定制密码列表,你可以有检查代码。 但大多数人不应该去想的密码列表,而不是它应该是默认使用普通的最佳实践。
此代码奇效意料不到的javax.net.ssl.SSLHandshakeException
。
升级到jdk1.8.0_92
和Oracle JCE无限制强度的政策文件并没有帮助,我是不成功的尝试特定应用SSLParameters
到HttpsUrlConnection
。
特别是,在尝试使用HttpsUrlConnection
阅读https://www.adrbnymellon.com
以下错误的结果:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
本网站之前,大约2016年4月15日工作确定,然后开始失败。 我相信失败是由于该网站停止支持造成SSLv2Hello
和SSLv3
由于淹死漏洞。 见这一个伟大的分析。
访问网站开始通过修改与变化,只是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?