代码之家  ›  专栏  ›  技术社区  ›  noah

android httpclient-证书中的主机名不匹配<example.com>!=<*.example.com>

  •  18
  • noah  · 技术社区  · 14 年前

    我在Android上使用httpclient连接到 https://someUrl.com/somePath . The problem is that the site's certificate is for *.someUrl.com, not someUrl.com, so I get an SSLException. Lame on the part of the site, yes, but unless I can get it fixed, I'm stuck. Is there a way I can get HttpClient to relax and accept the certificate?

    4 回复  |  直到 12 年前
        1
  •  33
  •   Nick Johnson    14 年前

    这是我的(编辑过的)解决方案:

    class MyVerifier extends AbstractVerifier {
    
        private final X509HostnameVerifier delegate;
    
        public MyVerifier(final X509HostnameVerifier delegate) {
            this.delegate = delegate;
        }
    
        @Override
        public void verify(String host, String[] cns, String[] subjectAlts)
                    throws SSLException {
            boolean ok = false;
            try {
                delegate.verify(host, cns, subjectAlts);
            } catch (SSLException e) {
                for (String cn : cns) {
                    if (cn.startsWith("*.")) {
                        try {
                              delegate.verify(host, new String[] { 
                                    cn.substring(2) }, subjectAlts);
                              ok = true;
                        } catch (Exception e1) { }
                    }
                }
                if(!ok) throw e;
            }
        }
    }
    
    
    public DefaultHttpClient getTolerantClient() {
        DefaultHttpClient client = new DefaultHttpClient();
        SSLSocketFactory sslSocketFactory = (SSLSocketFactory) client
                .getConnectionManager().getSchemeRegistry().getScheme("https")
                .getSocketFactory();
        final X509HostnameVerifier delegate = sslSocketFactory.getHostnameVerifier();
        if(!(delegate instanceof MyVerifier)) {
            sslSocketFactory.setHostnameVerifier(new MyVerifier(delegate));
        }
        return client;
    }
    

    它的优点是,除非存在通配符域,否则不会更改默认行为,在这种情况下,它会重新验证由两部分组成的域(例如someurl.com)是否是证书的一部分,否则原始异常会重新引发。这意味着真正无效的证书仍然会失败。

        2
  •  3
  •   Community George Stocker    7 年前

    Android上的BouncyCastle太旧,无法识别通配符证书。

    您可以编写自己的X509TrustManager来检查通配符。

    或者,如果可以接受风险,您可以完全禁用证书检查。看到这个问题,

    Self-signed SSL acceptance on Android

        3
  •  1
  •   Melody Horn    14 年前

    如果它想要 *.someUrl.com ,那么你似乎可以给它 www.someUrl.com/somePath 而不是 someUrl.com/somePath .

        4
  •  1
  •   Ayreon    13 年前

    如果使用WebView,只需调用

    webview.clearSslPreferences();
    

    忽略SSL错误