Google Play Security Alert - Your app is using an unsafe implementation of the HostnameVerifier
Asked Answered
J

6

13

Recently one of my app got a security alert from Google Play as below.

You app is using an unsafe implementation of the HostnameVerifier. And refer a link to Google Play Help Center article for details regarding to fixing and deadline of vulnerability.

Below is my code.

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
    public boolean verify(String arg0, SSLSession arg1) {
        return true;
}}); 

Anyone can explain with example about, what changes should I do to fix this warning?

Jurisdiction answered 2/12, 2016 at 9:10 Comment(4)
I too have same issue. Please list all libs that you are using. I can compare with mine and find out which one is causing problem.Blowup
Could it be Glide lib? Same issue here but no HostnameVerifier used in a project at all. Can't understand how could I change "my custom HostnameVerifier to make it return false" if I don't have any such implementations?Intensive
@Intensive I am not using Glide lib. I have added my code for HostnameVerifier in question.Jurisdiction
I understand but Glide is very popular Image downloading/caching lib and it uses Network (to DL images) and thus it could be the source of the issue. But if you don't use it then its not the case.Intensive
I
7

Same here - Insecure Hostname Verifier Detected in APK

Your app is using an unsafe implementation of HostnameVerifier. Please see this Google Help Center article for details, including the deadline for fixing the vulnerability. Im not using HostnameVerifier and not calling setDefaultHostnameVerifier. Moreover - Im using OKHTTP lib for http-requests. I hope that defining TrustManager will solve this issue.

Since I'm not subclassing HostnameVerifier or calling setDefaultHostnameVerifier() I assume it relies to some 3rd party lib. Since I can't detect such lib I think I will try to add a class with following code

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    public boolean verify(final String hostname, final SSLSession session) {
        if (/* check if SSL is really valid */)
            return true;
        else
            return false;
    }
});

to my project and will see if it fixes the issue.
So I did it and additionally to every webView I've added overridden method

@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    // the main thing is to show dialog informing user
    // that SSL cert is invalid and prompt him to continue without 
    // protection: handler.proceed();
    // or cancel: handler.cancel();
    String message;
    switch(error.getPrimaryError()) {
        case SslError.SSL_DATE_INVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_date_invalid);
            break;
        case SslError.SSL_EXPIRED:
            message = ResHelper.getString(R.string.ssl_cert_error_expired);
            break;
        case SslError.SSL_IDMISMATCH:
            message = ResHelper.getString(R.string.ssl_cert_error_idmismatch);
            break;
        case SslError.SSL_INVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_invalid);
            break;
        case SslError.SSL_NOTYETVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_not_yet_valid);
            break;
        case SslError.SSL_UNTRUSTED:
            message = ResHelper.getString(R.string.ssl_cert_error_untrusted);
            break;
        default:
            message = ResHelper.getString(R.string.ssl_cert_error_cert_invalid);
    }
    mSSLConnectionDialog = new MaterialDialog.Builder(getParentActivity())
            .title(R.string.ssl_cert_error_title)
            .content(message)
            .positiveText(R.string.continue_button)
            .negativeText(R.string.cancel_button)
            .titleColorRes(R.color.black)
            .positiveColorRes(R.color.main_red)
            .contentColorRes(R.color.comment_grey)
            .backgroundColorRes(R.color.sides_menu_gray)
            .onPositive(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                    mSSLConnectionDialog.dismiss();
                    handler.proceed();
                }
            })
            .onNegative(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                    handler.cancel();
                }
            })
            .build();
    mSSLConnectionDialog.show(); 
}

to the

mWebView.setWebViewClient(new WebViewClient() {
... // other corresponding overridden methods
}

And finally Google says:

SECURITY SCAN COMPLETE
No known vulnerabilities were detected for APK 158.

However I'm not sure what code made it, HostNameVerifier or onReceivedSslError() of mWebView.setWebViewClient. Note: HostNameVerifier.setDefaultHostnameVerifier() should not return true always like it is in your code! It has to implement some logic to check if its all OK with SSL and return true or false. It is essential.

Intensive answered 7/12, 2016 at 9:51 Comment(10)
Thanks for the helpful answer but how to check the APK before publish to ensure that warning was to avoid.Bots
AFAIK by uploading apk to Alpha or Beta only. This way app will not be available to regular users.Intensive
is it necessary to hace ssl certification in server. i am using http only. no ssl certificationGramarye
Google nowadays forcing to use only HTTP secure connections by default. Seems like unsecured HTTP will be deprecated and HTTPS will be a default connection type in a near future.Intensive
I did not create a class for HttpsURLConnection.setDefaultHostnameVerifier but rather created a method in MainApplication.java that implements this function and invoked it in the onCreate function. Is that correct?Twannatwattle
Please help, I have the below implementation. I am checking fixed hostnames and then returning true or false accordingly in the main applicaiton.java file. I have a react native App. ========= private void hostnameVerifier(){ HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { String hostList[] = {"dmn1", "dmn2","dmn3"}; for (String host : hostList) { if (host.contains(arg0) || arg0.endsWith(host)) { return true; } } return false; } }); }Twannatwattle
@Twannatwattle DId you find any solution for this? I am also using React Native and getting the same error.Wei
@Intensive@JJD can you please help me implementing this solution in React Native app.Wei
Sorry, I had never worked with React Native and thus can't help you on this...Intensive
@Twannatwattle your code actually allows any malicious actor to impersonate your trusted servers: "dmn1", "dmn2", and "dmn3". Is this what you really want?Freely
S
7
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
    public boolean verify(String arg0, SSLSession arg1) {
        return true;
}}); 

This code effectively removes the protection of HTTPS from your connections. You need to delete it.

Disabling hostname verification allows anyone on the network to view and tamper with your network traffic by conducting a Man In The Middle Attack.

Seng answered 6/12, 2016 at 20:35 Comment(0)
I
7

Same here - Insecure Hostname Verifier Detected in APK

Your app is using an unsafe implementation of HostnameVerifier. Please see this Google Help Center article for details, including the deadline for fixing the vulnerability. Im not using HostnameVerifier and not calling setDefaultHostnameVerifier. Moreover - Im using OKHTTP lib for http-requests. I hope that defining TrustManager will solve this issue.

Since I'm not subclassing HostnameVerifier or calling setDefaultHostnameVerifier() I assume it relies to some 3rd party lib. Since I can't detect such lib I think I will try to add a class with following code

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    public boolean verify(final String hostname, final SSLSession session) {
        if (/* check if SSL is really valid */)
            return true;
        else
            return false;
    }
});

to my project and will see if it fixes the issue.
So I did it and additionally to every webView I've added overridden method

@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    // the main thing is to show dialog informing user
    // that SSL cert is invalid and prompt him to continue without 
    // protection: handler.proceed();
    // or cancel: handler.cancel();
    String message;
    switch(error.getPrimaryError()) {
        case SslError.SSL_DATE_INVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_date_invalid);
            break;
        case SslError.SSL_EXPIRED:
            message = ResHelper.getString(R.string.ssl_cert_error_expired);
            break;
        case SslError.SSL_IDMISMATCH:
            message = ResHelper.getString(R.string.ssl_cert_error_idmismatch);
            break;
        case SslError.SSL_INVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_invalid);
            break;
        case SslError.SSL_NOTYETVALID:
            message = ResHelper.getString(R.string.ssl_cert_error_not_yet_valid);
            break;
        case SslError.SSL_UNTRUSTED:
            message = ResHelper.getString(R.string.ssl_cert_error_untrusted);
            break;
        default:
            message = ResHelper.getString(R.string.ssl_cert_error_cert_invalid);
    }
    mSSLConnectionDialog = new MaterialDialog.Builder(getParentActivity())
            .title(R.string.ssl_cert_error_title)
            .content(message)
            .positiveText(R.string.continue_button)
            .negativeText(R.string.cancel_button)
            .titleColorRes(R.color.black)
            .positiveColorRes(R.color.main_red)
            .contentColorRes(R.color.comment_grey)
            .backgroundColorRes(R.color.sides_menu_gray)
            .onPositive(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                    mSSLConnectionDialog.dismiss();
                    handler.proceed();
                }
            })
            .onNegative(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                    handler.cancel();
                }
            })
            .build();
    mSSLConnectionDialog.show(); 
}

to the

mWebView.setWebViewClient(new WebViewClient() {
... // other corresponding overridden methods
}

And finally Google says:

SECURITY SCAN COMPLETE
No known vulnerabilities were detected for APK 158.

However I'm not sure what code made it, HostNameVerifier or onReceivedSslError() of mWebView.setWebViewClient. Note: HostNameVerifier.setDefaultHostnameVerifier() should not return true always like it is in your code! It has to implement some logic to check if its all OK with SSL and return true or false. It is essential.

Intensive answered 7/12, 2016 at 9:51 Comment(10)
Thanks for the helpful answer but how to check the APK before publish to ensure that warning was to avoid.Bots
AFAIK by uploading apk to Alpha or Beta only. This way app will not be available to regular users.Intensive
is it necessary to hace ssl certification in server. i am using http only. no ssl certificationGramarye
Google nowadays forcing to use only HTTP secure connections by default. Seems like unsecured HTTP will be deprecated and HTTPS will be a default connection type in a near future.Intensive
I did not create a class for HttpsURLConnection.setDefaultHostnameVerifier but rather created a method in MainApplication.java that implements this function and invoked it in the onCreate function. Is that correct?Twannatwattle
Please help, I have the below implementation. I am checking fixed hostnames and then returning true or false accordingly in the main applicaiton.java file. I have a react native App. ========= private void hostnameVerifier(){ HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { String hostList[] = {"dmn1", "dmn2","dmn3"}; for (String host : hostList) { if (host.contains(arg0) || arg0.endsWith(host)) { return true; } } return false; } }); }Twannatwattle
@Twannatwattle DId you find any solution for this? I am also using React Native and getting the same error.Wei
@Intensive@JJD can you please help me implementing this solution in React Native app.Wei
Sorry, I had never worked with React Native and thus can't help you on this...Intensive
@Twannatwattle your code actually allows any malicious actor to impersonate your trusted servers: "dmn1", "dmn2", and "dmn3". Is this what you really want?Freely
P
5

Please check my code I have only verified domains that my app uses. In your code you must verify all domains your app uses. I have used my server and Fabric.com so my code is below

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession arg1) {
        if (hostname.equalsIgnoreCase("api.my.com") || 
            hostname.equalsIgnoreCase("api.crashlytics.com") || 
            hostname.equalsIgnoreCase("settings.crashlytics.com")) {
            return true;
        } else {
            return false;
        }
    }
});
Paratrooper answered 30/12, 2016 at 8:53 Comment(0)
P
2

On google play console go to Release Management -> Select apk version -> Security tab. There you will see list of security issues with that apk along with class in your code that's causing that security issue where ever possible.

enter image description here

Platus answered 12/1, 2018 at 17:22 Comment(1)
If you do not see a class name and rather see some encoded code in the security warning message, upload another build by disabling whatever code compress tool you maybe using. In my case it was proguard, I disabled it and got the library name. FYI - THe library was Braintree in my case.Twannatwattle
H
0
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession arg1) {
        if (!hostname.equalsIgnoreCase("www.asdasdad.com"))
            return true;
        else
            return false;
    }
});

It works

Hardball answered 8/3, 2017 at 16:18 Comment(2)
It surely will work bcos you are returning true when hostname is not equal to domain name!Albertson
This is not the real way to handle this issue. either you need to use a proper ssl or handle the SSL error with proper message. Otherwise what is the use of using SSLDishman
M
0

If you're using Braintree for Paypal payment.

Unsafe implementation of the HostnameVerifier interface - Google policy violation can also be caused due to the latest Braintree credentials update.

Please update below credentials and URL in build.gradle(Project)

Old Credentials

url  "https://cardinalcommerce.bintray.com/android"
username 'braintree-team-sdk@cardinalcommerce'
password '220cc9476025679c4e5c843666c27d97cfb0f951'

New Credentials

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url "https://cardinalcommerceprod.jfrog.io/artifactory/android"
            credentials {
                username 'braintree_team_sdk'
                password 'AKCp8jQcoDy2hxSWhDAUQKXLDPDx6NYRkqrgFLRc3qDrayg6rrCbJpsKKyMwaykVL8FWusJpp'
            }
        }
    }
}

If you're using the Google Play Services Gradle plugin, you will also need to add this to your build.gradle to avoid a dependency resolution issue:

components.all {
    allVariants {
        withDependencies { deps ->
            deps.each { dep ->
                if (dep.group == 'net.minidev' && dep.name =='json-smart') {
                    dep.version {
                        prefer "2.3"
                    }
                    dep.because "resolving dependencies issue"
                }
            }
        }
    }
}

StackOverflow: Braintree Drop-in UI: ERROR: Failed to resolve: org.jfrog.cardinalcommerce.gradle:cardinalmobilesdk:2.2.1-2?

For more info: https://developer.paypal.com/braintree/docs/guides/3d-secure/client-side/android/v3#generate-a-client-token

Related Git Thread regarding: https://github.com/braintree/braintree-android-drop-in/issues/219

Mechanic answered 7/7, 2021 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.