OKHttp Android не подключается к nginx через http2 alpn

У меня есть приложение для Android (4.4.4+), в котором используются следующие библиотеки:

compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
compile 'com.squareup.okio:okio:1.7.0'

У меня есть nginx (версия 1.9.14), скомпилированный с OpenSSL (исходный код версии 1.0.2g), использование openSSL подтверждено с помощью nginx -V на CentOS 7. Конфигурация nginx http2 включена для обратного прокси:

 server {
            listen  443 ssl http2;
            ssl     on;
            server_name     mobile.site.com;
            ssl_certificate         /etc/pki/tls/certs/start_cert.pem;
            ssl_certificate_key     /etc/pki/tls/certs/start_cert.key;
            proxy_cache     one;
            underscores_in_headers  on;
            access_log      /var/log/nginx/ssl.log ssl_custom;
            location / {
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $remote_addr;
                    proxy_set_header Host $host;
                    proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
                    proxy_pass https://10.10.1.31:443;
            }
    }

Запуск команды на сервере:

echo | openssl s_client -alpn h2 -connect

Возврат:

No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3718 bytes and written 442 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
ALPN protocol: h2

При просмотре URL-адреса API из любого современного браузера в журналах SSL и в надстройке HTTP / 2 Chrome отображается соединение HTTP / 2. Предполагая, что HTTP / 2 правильно настроен в nginx / OpenSSL.

Клиенты Android OKHttp отказываются от HTTP / 2:

            ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();
            okHttpClient = new OkHttpClient.Builder()
                    .followSslRedirects(true)
                    .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
                    .connectionSpecs(Collections.singletonList(spec))
                    .sslSocketFactory(new TLSSocketFactory((SSLSocketFactory) TLSSocketFactory.getDefault()))
                    .retryOnConnectionFailure(true)
                    .connectTimeout(25, TimeUnit.SECONDS)
                    .connectionPool(new ConnectionPool(30, 120, TimeUnit.SECONDS))
                    .addInterceptor(new AddCookiesInterceptor())
                    .addInterceptor(new ReceivedCookiesInterceptor())
                    .build();

Я написал настраиваемую фабрику сокетов TLS, позволяющую использовать TLS 1.2 на ‹= Android 4.4.4.

TLSv1.2 действительно работает на 4.4.4+ с этой настраиваемой фабрикой сокетов, но я также пробовал работать на 5.0+ с настраиваемой фабрикой сокетов и без нее, не повезло с HTTP / 2.

HTTP / 2 не работает на kit-kat, lollipop и marshmallow, но работает в предварительной версии для разработчиков N (также известной как New York Cheesecake). Никаких ошибок не возникает, просто всегда подключается как HTTP / 1.1. У меня возникают проблемы с поиском статей, относящихся к OKhttp и HTTP / 2, в большинстве справочных вопросов / сообщений просто говорится об использовании ALPN, но нет ресурсов, чтобы подробно рассказать об использовании. В документации OkHTTP нет ясности в отношении использования и практики развертывания HTTP / 2, но на главной странице говорится, что он поддерживает его. Мы будем очень благодарны за любую помощь или руководство, даже просто толчок в правильном направлении будет огромным подспорьем. Пожалуйста, дайте мне знать, если я пропустил что-нибудь, что может помочь в процессе, заранее спасибо!

Обновление 1. Я нашел один из связанных с этим вопросов SO с очень расплывчатым ответом: [SO link] https://stackoverflow.com/questions/31850249/how-to-use-http-2-with-okhttp-on-android-devices?Rq=1 с комментарием, в котором предлагается использовать причал, но только в отношении рабочего стола использование, а не использование Android.

Обновление 2: в этой статье показано, что ALPN включен в Android 4.4: https://github.com/http2/http2-spec/wiki/ALPN-Status

Обновление 3: удалось подключить HTTP / 2 с использованием +5.0, но не 4.4.4. Мне не нужно опускаться ниже 4.4.4, так как внутренние целевые устройства являются проблемой для http / 2, и они работают с 4.4.4. Мне удалось обновить приложение, чтобы использовать протокол безопасности Google Play Services в качестве подключения сокета OKHttp, но используемые нами устройства 4.4.4 не поддерживают Google, поэтому я не могу использовать на них защитные сокеты PlayServices.


person DoctorD    schedule 19.04.2016    source источник
comment
Провел еще несколько исследований используемых шифров, пытаясь найти шаблон: 4.4.4: TLSv1.2 ECDHE-RSA-AES128-SHA - 5.1.1: TLSv1. 2 ECDHE-RSA-AES128-GCM-SHA256 - 6.0: TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 - 7.0: TLSv1.2 ECDHE-RSA-AES128 -GCM-SHA256 - Chrome / FireFox: TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256. Только Chrome / FireFox и 7.0 (N) подключаются по HTTP / 2.   -  person DoctorD    schedule 21.04.2016
comment
Есть обновления по этому поводу? Удалось ли вам установить http2 на 4.4.4 или вы собираетесь использовать другую альтернативу?   -  person Zasz    schedule 05.11.2016
comment
В данный момент я перешел к другим вещам, но я хочу вернуться сюда в ближайшее время. Я могу посмотреть завтра и посмотреть, что я могу сделать с любыми обновленными библиотеками.   -  person DoctorD    schedule 07.11.2016
comment
Кажется, есть новый (расширенный) метод в OkHttpClient.Builder sslSocketFactory. Исходный метод (устаревший) требовал только sslSocketFactory, однако новому методу требуются sslSocketFactory и X509TrustFactory. Здесь может что-то быть, но мне нужно будет исследовать следующий цикл сборки, если это повлияет. Мое ограниченное понимание состоит в том, что встроенный в провайдер сертификатов Android (‹5.0) не имеет правильного способа установления связи с сертификатами HTTP2 SSL. Возможно, есть способ использовать поставщика сертификатов Google Play, но на моих целевых устройствах не включена GMS.   -  person DoctorD    schedule 08.11.2016


Ответы (1)


Согласно swankjesse,

Следующие шаги: не используйте ALPN на Android 4.4 и более ранних версиях; там он сломан. Восстановите NPN для версий Android, где он был ранее стабильным.

Не используйте сломанный ALPN на Android 4.4

person Sunbreak    schedule 16.05.2017
comment
Настоящий вопрос заключался в том, как заставить HTTP2 работать на ‹5 устройствах SDK. HTTP2 SPEC показывает, что он должен работать с 4.4 с использованием NPN или ALPN. К сожалению, NGINX удалил поддержку NPN и использует только ALPN, а OKHTTP удалил поддержку восстановления после сбоя, поэтому они никогда не будут подключаться. - person DoctorD; 18.05.2017