Как переопределить шифрованный список, отправленный на сервер Android при использовании HttpsURLConnection?

Во время переговоров TLS клиенты отправляют список поддерживаемых шифров на сервер, сервер выбирает один, и начинается шифрование. Я хочу изменить этот шифрованный список, отправленный на сервер Android, когда я использую HttpsURLConnection для связи.

Я знаю, что я могу использовать setSSLSocketFactory HttpsURLConnection объекта HttpsURLConnection чтобы настроить его для использования SSLSocketFactory . Это полезно, когда я хочу изменить trustmanager и т. Д., Используемый SSLSocket возвращенный SSLSocketFactory .

Я знаю, что в целом этот список ciphersuite можно редактировать с помощью объекта SSLParameters и передавать его в SSlsocket или SSLEngine используя методы, которые они предоставляют.

НО SSLSocketFactory , похоже, не раскрывает такие методы!

Я не могу найти способ изменить SSLParameters возвращаемых объектов SSLSocket созданных SSLSocketFactory я HttpsURLConnection .

Что делать?

Думаю, это относится и к Java в целом, а не только к Android. Может быть, есть способ OO (например, расширить SSLSocketFactory и предоставить это HttpsURLConnection ?)

Этот fragment кода немного сырой. используйте с осторожностью.

 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 suitesList = new ArrayList(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 suitesList = new ArrayList(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 для получения современной конфигурации TLS при использовании HttpsURLConnection Android. 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

Этот сайт работал нормально до примерно 4/15/2016, а затем начал сбой. Я считаю, что неудача вызвана тем, что веб-сайт прекратил поддержку 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"); 

Надеюсь, это поможет кому-то другому.

  • Как передать строку из одной активности в другую?
  • Как вы используете Intent.FLAG_ACTIVITY_CLEAR_TOP, чтобы очистить стек активности?
  • Как правильно строить банки от IntelliJ?
  • Как установить выбранный элемент Spinner по значению, а не положением?
  • Защищенные поля Java vs public getters
  • Заполнение ListView с помощью ArrayList?
  • Android и получение представления с литой идентификатором в виде строки
  • Как поймать особые исключения Firebase Auth
  • android, что не так с openFileOutput?
  • Замена fragmentа другим fragmentом внутри группы действий
  • Переменные среды для установки Java
  • Давайте будем гением компьютера.