How to override the cipherlist sent to the server by Android when using HttpsURLConnection?
在TLS协商期间,客户端将支持的密码列表发送到服务器,服务器选择一个,然后开始加密。 当我使用
我知道我可以在
我知道,通常可以使用
但是
我找不到改变我传给
该怎么办?
我猜想这不仅与Android有关,而且与Java有关。 也许有一种OO方法可以做到这一点(例如扩展
这段代码有点原始。请谨慎使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 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()]); } } |
当您想使用它时。
1 2 3 4 5 6 7 8 | 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的answer1中的技术捆绑为无效的简单方法调用。使用Android的
1 | compile 'info.guardianproject.netcipher:netcipher:1.2' |
或者,您可以下载netcipher-1.2.jar并将其直接包含在您的应用程序中。然后,而不是调用:
1 |
叫这个:
1 | HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl); |
如果要专门自定义该密码列表,可以在此处检查代码。但是大多数人不必考虑密码列表,而是默认情况下应使用常见的最佳做法。
这段代码为意外的
升级到
特别是,尝试使用
该网站在2016年4月15日之前运行正常,然后开始失败。我相信该故障是由于DROWN漏洞导致网站不再支持
通过仅更改2个常量来修改代码,从而开始访问网站:
1 2 | private static final String PREFERRED_CIPHER_SUITE ="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; SSLContext context = SSLContext.getInstance("TLSv1.2"); |
我希望这可以帮助其他人。