Подтвердить что ты не робот

Webview избегает предупреждения безопасности из игры Google при реализации onReceivedSslError

У меня есть ссылка, которая откроется в webview. Проблема в том, что он не может быть открыт, пока я не переопределяю onReceivedSslError следующим образом:

 @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }

Я получаю предупреждение о безопасности от игры Google, говоря:

Предупреждение о безопасности В вашем приложении небезопасная реализация обработчика WebViewClient.onReceivedSslError. В частности, реализация игнорирует все ошибки проверки сертификата SSL, делая ваше приложение уязвимым для атак типа "человек в середине". Злоумышленник может изменить затронутый контент WebView, прочитать переданные данные (например, учетные данные для входа) и выполнить код внутри приложения с помощью JavaScript.

Чтобы правильно обрабатывать SSL-сертификат, измените свой код, чтобы вызывать SslErrorHandler.proceed(), когда сертификат, представленный сервером, соответствует вашим ожиданиям и вызывает в противном случае SslErrorHandler.cancel(). На ваш адрес учетной записи разработчика отправлено уведомление по электронной почте, содержащее затронутые приложения и классы (ы).

Просьба устранить эту уязвимость как можно скорее и увеличить номер версии обновленного APK. Дополнительные сведения о обработчике ошибок SSL см. В нашей документации в Справочном центре разработчика. По другим техническим вопросам вы можете отправить сообщение https://www.stackoverflow.com/questions и использовать теги "android-security" и "SslErrorHandler". Если вы используете стороннюю библиотеку, которая отвечает за это, сообщите об этом третьей стороне и поработайте с ними, чтобы решить эту проблему.

Чтобы убедиться, что вы правильно обновили, загрузите обновленную версию в консоль разработчика и загляните назад через пять часов. Если приложение не было правильно обновлено, появится предупреждение.

Обратите внимание, что, хотя эти конкретные проблемы могут не повлиять на каждое приложение, использующее WebView SSL, лучше всего оставаться в курсе всех патчей безопасности. Приложения с уязвимостями, которые подвергают пользователей риску компрометации, могут считаться опасными продуктами в нарушение Политики контента и раздела 4.4 Соглашения о распространении программного обеспечения.

Пожалуйста, убедитесь, что все опубликованные приложения соответствуют Соглашению о распространении программного обеспечения и Политике контента. Если у вас есть вопросы или проблемы, обратитесь в нашу службу поддержки через Справочный центр разработчика Google Play.

Если я удалю onReceivedSslError (handler.proceed()), страница не откроется.

В любом случае я могу открыть страницу в веб-браузере и избежать предупреждения о безопасности.

4b9b3361

Ответ 1

Чтобы правильно обработать проверку сертификата SSL, измените код на вызывать SslErrorHandler.proceed(), когда сертификат, представленный сервер отвечает вашим ожиданиям и вызывает SslErrorHandler.cancel() в противном случае.

Как говорится в сообщении электронной почты, onReceivedSslError должен обрабатывать пользователя, переходит на страницу с недопустимым сертификатом, например, в диалоговом окне уведомления. Вы не должны действовать прямо.

Например, я добавляю диалоговое окно предупреждения, чтобы пользователь подтвердил и, похоже, Google больше не показывает предупреждение.


@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(R.string.notification_error_ssl_cert_invalid);
    builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.proceed();
        }
    });
    builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.cancel();
        }
    });
    final AlertDialog dialog = builder.create();
    dialog.show();
}

Подробнее объясните по электронной почте.

В частности, реализация игнорирует всю проверку сертификата SSL ошибок, делая ваше приложение уязвимым для атак типа "человек в центре".

В сообщении электронной почты указано, что реализация по умолчанию игнорировала важную проблему безопасности SSL. Поэтому нам нужно обработать его в нашем собственном приложении, которое использовало WebView. Уведомлять пользователя с диалоговым окном оповещения - это простой способ.

Ответ 2

Исправление, которое работает для меня, - это просто отключить функцию onReceivedSslError, определенную в AuthorizationWebViewClient. В этом случае handler.cancel будет вызываться в случае ошибки SSL. Однако он отлично работает с сертификатами SSL для одного диска. Протестировано на Android 2.3.7, Android 5.1.

Ответ 3

Согласно Предупреждение о безопасности Google: небезопасная реализация интерфейса X509TrustManager, Google Play не будет поддерживать X509TrustManager с 11 июля 2016 года:

Привет, разработчик Google Play,

В ваших приложениях, перечисленных в конце этого письма, используется небезопасное реализация интерфейса X509TrustManager. В частности, реализация игнорирует все ошибки проверки сертификата SSL, когда установление HTTPS-соединения с удаленным хостом, тем самым приложение уязвимо для атак типа "человек-в-середине". Злоумышленник может читать передаваемые данные (такие как учетные данные для входа) и даже изменение данных передается по HTTPS-соединению. Если у вас более 20 затронутых приложений в вашей учетной записи, пожалуйста, проверьте консоль разработчика для полного список.

Чтобы правильно обрабатывать SSL-сертификат, измените код в checkServerTrusted метод вашего пользовательского интерфейса X509TrustManager для поднять либо CertificateException, либо IllegalArgumentException всякий раз сертификат, представленный сервером, не соответствует вашему ожидания. По техническим вопросам вы можете отправлять сообщения в Qaru и используйте теги "android-security" и "TrustManager".

Просьба решить эту проблему как можно скорее и увеличить номер версии обновленного APK. С 17 мая 2016 года Google Play заблокирует публикацию любых новых приложений или обновлений, содержащих небезопасная реализация интерфейса X509TrustManager.

Чтобы подтвердить, что вы внесли правильные изменения, отправьте обновленную версию вашего приложения в Консоль разработчика и проверить его через пять часов. Если приложение не было правильно обновлено, появится предупреждение.

Хотя эти конкретные проблемы могут не влиять на каждое приложение с помощью TrustManager, лучше всего не игнорировать сертификат SSL ошибки проверки. Приложения с уязвимостями, которые подвергают пользователей риску компромисса могут считаться опасными продуктами в нарушение Политика контента и раздел 4.4 дистрибутива разработчика Соглашение.

...

Ответ 4

Вы можете использовать SslError для показа, некоторую информацию об ошибке этого сертифицированного, и вы можете написать в своем диалоговом окне строку ошибки типа.

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    final SslErrorHandler handlerFinal;
    handlerFinal = handler;
    int mensaje ;
    switch(error.getPrimaryError()) {
        case SslError.SSL_DATE_INVALID:
            mensaje = R.string.notification_error_ssl_date_invalid;
            break;
        case SslError.SSL_EXPIRED:
            mensaje = R.string.notification_error_ssl_expired;
            break;
        case SslError.SSL_IDMISMATCH:
            mensaje = R.string.notification_error_ssl_idmismatch;
            break;
        case SslError.SSL_INVALID:
            mensaje = R.string.notification_error_ssl_invalid;
            break;
        case SslError.SSL_NOTYETVALID:
            mensaje = R.string.notification_error_ssl_not_yet_valid;
            break;
        case SslError.SSL_UNTRUSTED:
            mensaje = R.string.notification_error_ssl_untrusted;
            break;
        default:
            mensaje = R.string.notification_error_ssl_cert_invalid;
    }

    AppLogger.e("OnReceivedSslError handel.proceed()");

    View.OnClickListener acept = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            dialog.dismiss();
            handlerFinal.proceed();
        }
    };

    View.OnClickListener cancel = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            dialog.dismiss();
            handlerFinal.cancel();
        }
    };

    View.OnClickListener listeners[] = {cancel, acept};
    dialog = UiUtils.showDialog2Buttons(activity, R.string.info, mensaje, R.string.popup_custom_cancelar, R.string.popup_custom_cancelar, listeners);    }

Ответ 5

Мне нужно было проверить наш магазин доверия, прежде чем показывать какое-либо сообщение пользователю, поэтому я сделал это:

public class MyWebViewClient extends WebViewClient {
private static final String TAG = MyWebViewClient.class.getCanonicalName();

Resources resources;
Context context;

public MyWebViewClient(Resources resources, Context context){
    this.resources = resources;
    this.context = context;
}

@Override
public void onReceivedSslError(WebView v, final SslErrorHandler handler, SslError er){
    // first check certificate with our truststore
    // if not trusted, show dialog to user
    // if trusted, proceed
    try {
        TrustManagerFactory tmf = TrustManagerUtil.getTrustManagerFactory(resources);

        for(TrustManager t: tmf.getTrustManagers()){
            if (t instanceof X509TrustManager) {

                X509TrustManager trustManager = (X509TrustManager) t;

                Bundle bundle = SslCertificate.saveState(er.getCertificate());
                X509Certificate x509Certificate;
                byte[] bytes = bundle.getByteArray("x509-certificate");
                if (bytes == null) {
                    x509Certificate = null;
                } else {
                    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
                    Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
                    x509Certificate = (X509Certificate) cert;
                }
                X509Certificate[] x509Certificates = new X509Certificate[1];
                x509Certificates[0] = x509Certificate;

                trustManager.checkServerTrusted(x509Certificates, "ECDH_RSA");
            }
        }
        Log.d(TAG, "Certificate from " + er.getUrl() + " is trusted.");
        handler.proceed();
    }catch(Exception e){
        Log.d(TAG, "Failed to access " + er.getUrl() + ". Error: " + er.getPrimaryError());
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        String message = "SSL Certificate error.";
        switch (er.getPrimaryError()) {
            case SslError.SSL_UNTRUSTED:
                message = "O certificado não é confiável.";
                break;
            case SslError.SSL_EXPIRED:
                message = "O certificado expirou.";
                break;
            case SslError.SSL_IDMISMATCH:
                message = "Hostname inválido para o certificado.";
                break;
            case SslError.SSL_NOTYETVALID:
                message = "O certificado é inválido.";
                break;
        }
        message += " Deseja continuar mesmo assim?";

        builder.setTitle("Erro");
        builder.setMessage(message);
        builder.setPositiveButton("Sim", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                handler.proceed();
            }
        });
        builder.setNegativeButton("Não", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                handler.cancel();
            }
        });
        final AlertDialog dialog = builder.create();
        dialog.show();
    }
}
}