HostnameVerifier 接口的不安全实现 - Android

Posted

技术标签:

【中文标题】HostnameVerifier 接口的不安全实现 - Android【英文标题】:Unsafe implementation of the HostnameVerifier interface - Android 【发布时间】:2021-10-02 09:00:51 【问题描述】:

应用在 Play 商店被拒绝的原因:

您的应用正在使用 HostnameVerifier 接口的不安全实现。您可以在此Google Help Center article. 中找到有关如何解决此问题的更多信息

大家好,

当我将应用程序上传到 Play 商店时,Google Play 控制台出现 HostnameVerifier 问题。我已经尝试了在 *** 上找到的所有解决方案,但问题仍然存在,即 您的应用正在使用 HostnameVerifier 接口的不安全实现。

另外,我已经通过谷歌documentation 解决了这个问题,但没有得到任何运气。有没有人对此有解决方案?感谢您的每一次帮助

下面是我的ServiceGenerator

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);
    

【问题讨论】:

去掉你在代码 sn-p 中看到的HostnameVerifier。一路走来,摆脱“全信信任管理器”,这更不安全。 从您的应用程序的其余部分中删除任何类似的HostnameVerifier 实例。确保您了解所有依赖项的最新信息。 @CommonsWare 我已经从整个应用程序中删除了HostnameVerifier 实例。还将应用上传到测试版,但由于此问题,应用仍然被拒绝 你摆脱了“全信信任经理”吗?如果没有,请这样做。除此之外,您还需要尝试查看您的任何依赖项是否也在做这种事情。 好的,我试试。感谢@CommonsWare 的帮助 【参考方案1】:

实际上,这个问题是由于使用 HostnamVerifier 的 Braintree SDK 造成的。我已经为 Braintree 浏览了这个 GitHub 问题 channel 并且知道他们已经解决了这个问题,我只需要更新 SDK 版本并再次将包上传到 Play 商店。这解决了我的问题,并且能够将我的应用上传到 Play 商店。

任何人仍在寻找更好的解决方案但无法在任何地方找到它,请通过此link 并在那里提交您的问题详细信息,还请让他们提及导致的文件的名称这个问题。他们会在邮件中以文件名回复您。

【讨论】:

以上是关于HostnameVerifier 接口的不安全实现 - Android的主要内容,如果未能解决你的问题,请参考以下文章

Android 中不安全的 HostnameVerifier - React Native

来自 Google Play 商店的 Android React Native App HostNameVerifier 错误

配置Jetty HTTP / 2客户端以使用我的HostnameVerifier实现

httpsUrlConnection 如何设置的默认sslcontext和 hostnameverifier?

httpsUrlConnection 如何设置的默认sslcontext和 hostnameverifier?

Swift 的不安全