2

Reason for app rejection on Play Store:

Your app(s) are using an unsafe implementation of the HostnameVerifier interface. You can find more information about how to resolve the issue in this Google Help Center article.

Hello All,

I'm getting a HostnameVerifier issue by google play console when I upload the app to the play store. I've tried each and every solution that I've found on StackOverflow, but still, the issue is the same i.e Your app(s) are using an unsafe implementation of the HostnameVerifier interface.

Also, I've gone through the google documentation for this issue but didn't get any luck. Does anyone have a solution regarding this? Every help is appreciated

Below is my ServiceGenerator class

public class ServiceGenerator {

    private static final String KEY_AUTH_HEADER = "Authorization";
    private Context context;
    private Retrofit.Builder builder;
    private OkHttpClient.Builder httpClient;
    HandshakeCertificates certificates;

    ServiceGenerator(Context context) {
        this.context = context;
        final String dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'";

        httpClient = new OkHttpClient.Builder();

        certificates = new HandshakeCertificates.Builder()
                .addTrustedCertificate(AppConstants.SSL_CERTIFICATE_DEMO)
                .addTrustedCertificate(AppConstants.SSL_CERTIFICATE_LIVE)
                // Uncomment if standard certificates are also required.
                .addPlatformTrustedCertificates()
                .build();

        // Install the all-trusting trust manager
        final SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new X509TrustManager[]{certificates.trustManager()}, new java.security.SecureRandom());

            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            httpClient.sslSocketFactory(sslSocketFactory, certificates.trustManager());
            httpClient.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
       
        httpClient.connectTimeout(60, TimeUnit.SECONDS);
        httpClient.readTimeout(60, TimeUnit.SECONDS);
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

        int cacheSize = 20 * 1024 * 1024; // 20 MB
        Cache cache = new Cache(context.getCacheDir(), cacheSize);

        logging.level(HttpLoggingInterceptor.Level.BASIC);

        httpClient.cache(cache);
        httpClient.addNetworkInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response originalResponse = chain.proceed(chain.request());
                if (Functions.isConnected(context)) {
                    int maxAge = 60 * 2; // read from cache for 2 minute
                    return originalResponse.newBuilder()
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .build();
                } else {
                    int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
                    return originalResponse.newBuilder()
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .build();
                }
            }
        });

        httpClient.addInterceptor(logging);
        httpClient.addInterceptor(new HeaderInterceptor());

        Gson gson = new GsonBuilder()
                .setDateFormat(dateFormat)
                .create();
        builder = new Retrofit.Builder()
                .baseUrl(Apis.HOST);

        builder.addConverterFactory(GsonConverterFactory.create(gson));
    }

    class HeaderInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {

            String authKey = "authKey";
            if (PrefUtils.isUserLoggedIn(context) && PrefUtils.getUserFullProfileDetails(context) != null) {
                authKey = PrefUtils.getUserFullProfileDetails(context).getAuthKey();
            }

            Request newRequest = chain.request().newBuilder()
                    .addHeader("auth-key", authKey)
                    .build();
            return chain.proceed(newRequest);
        }
    }

    public <S> S createService(Class<S> serviceClass) {
        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(serviceClass);
    }
}
MashukKhan
  • 1,946
  • 1
  • 27
  • 46
  • 2
    Get rid of the `HostnameVerifier` that you see in your code snippet. Along the way, get rid of the "all-trusting trust manager", which is even less secure. – CommonsWare Jul 26 '21 at 12:16
  • 1
    Remove any similar `HostnameVerifier` instances from the rest of your app. Make sure you are up to date on all dependencies. – CommonsWare Jul 26 '21 at 12:47
  • @CommonsWare I've removed `HostnameVerifier` instances from the whole app. Also uploaded app to beta version but still app got rejected due to this issue – MashukKhan Jul 29 '21 at 04:06
  • Did you get rid of the "all-trusting trust manager"? If not, do so. Beyond that, you will need to try to see if any of your dependencies is doing this sort of thing as well. – CommonsWare Jul 29 '21 at 10:57
  • Okay, I'll try that. Thanks for the help @CommonsWare – MashukKhan Jul 29 '21 at 11:56
  • @MashukKhan Hi there, have you solved this problem? I'm confused a long time. I removed all implementations of HostnameVerifier from my App and still received warning from Play Store. – Jospehus Chou Aug 23 '21 at 02:50
  • @MashukKhan And I use OKHttp 4.8.1. Is it possible that the warning caused by OkHostnameverifier? – Jospehus Chou Aug 23 '21 at 03:01
  • Hi @JospehusChou, No I'm still getting this warning from the play store I've discussed it with the google developer and came to know that they have updated their security policies, and according to their policies, in my project, PayPal SDK is not meeting their policies. So for that, I'll be posting question soon . – MashukKhan Aug 23 '21 at 03:41
  • @MashukKhan Thank you, I will try to contact with Google developer support team to find out where is the problem in my App. – Jospehus Chou Aug 23 '21 at 05:58
  • @JospehusChou This is the [link](https://support.google.com/googleplay/android-developer/contact/app_vuln) if you want to submit your issue details, also ask them to specify which file is violating the security policy – MashukKhan Aug 23 '21 at 06:39
  • Hello, @JospehusChou I found the solution and updated my app to the play store & it got approved. If you are having the same issue with Braintree Paypal SDK then refer to this [link](https://github.com/braintree/braintree-android-drop-in/issues/208) – MashukKhan Sep 08 '21 at 04:47

1 Answers1

0

Actually, this issue was due to Braintree SDK which was using HostnamVerifier. I've gone through this GitHub issue channel for Braintree and came to know that they had resolved that issue and I just need to update the SDK version and again upload the bundle to the play store. This resolved my issue and was able to upload my app to the play store.

Whosoever is still looking for a better solution and didn't able to find it out anywhere then kindly go through this link and submit your issue details there, also please ask them to mention the name of the file which is causing this issue. They will revert you in the mail with the name of the file.

MashukKhan
  • 1,946
  • 1
  • 27
  • 46