问题 如何使用HttpsURLConnection覆盖Android发送到服务器的密码列表?
在TLS协商期间,客户端将支持的密码列表发送到服务器,服务器选择一个密码,然后开始加密。我想在我使用时更改此Android发送到服务器的密码列表 HttpsURLConnection
用于沟通。
我知道我可以使用 setSSLSocketFactory
在...上 HttpsURLConnection
将对象设置为使用a SSLSocketFactory
。当我想要更改使用的trustmanager等时,这很有用 SSLSocket
由...返回 SSLSocketFactory
。
我知道一般来说这个密码列表可以用。编辑 SSLParameters
对象并将其传递给 SSlsocket
要么 SSLEngine
对象使用它们提供的方法。
但是 SSLSocketFactory
似乎没有公开这样的方法!
我找不到改变方法 SSLParameters
返回的 SSLSocket
由...创建的对象 SSLSocketFactory
我转到了 HttpsURLConnection
。
该怎么办?
我想这也与Java有关,不仅仅是Android。也许有一种OO方式可以做到(例如扩展 SSLSocketFactory
并提供给 HttpsURLConnection
?)
7370
2018-04-30 12:06
起源
答案:
这段代码有点原始。请小心使用。
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();
谢谢。
13
2018-05-23 12:33
答案:
这段代码有点原始。请小心使用。
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();
谢谢。
13
2018-05-23 12:33
我在@ 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);
如果要专门自定义该密码列表,可以在那里检查代码。但是大多数人不应该考虑密码列表,而应该默认使用常见的最佳实践。
3
2017-11-06 15:27
这段代码出乎意料的奇迹 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
由于DROWN漏洞。看到 这个 进行了很好的分析。
访问网站开始工作,修改代码只需更改2个常量:
private static final String PREFERRED_CIPHER_SUITE = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
SSLContext context = SSLContext.getInstance("TLSv1.2");
我希望这有助于其他人。
-1
2018-04-22 17:57