修复X509TrustManager审核不过的问题

本文讨论的是在无合法CA证书,但又必须使用HTTPS API,Google应用审核通不过的处理方式。

从HTTP请求转成HTTPS,我们需要自定义X509TrustManager,因为使用无效CA证书,所以也不能实现安全校验逻辑,否则无法调用到正常的流程,代码如下:

TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
              //do nothing,接受任意客户端证书
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
              //do nothing,接受任意服务端证书
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};

以这样的代码打包出来的APK提交到Google Play Store后就是看运气,有可能没查到就让你通过了,有可能查到,就是拒绝,以下就是被拒情况下的处理方法:

一、使用伪认证

假装认证,抛出异常:

   public class TrustAllManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            if (arg0 == null){
                throw new IllegalArgumentException("X509Certificate array is null");
            }
            if (!(arg0.length > 0)){
                throw new IllegalArgumentException("X509Certificate is empty");
            }
            if (!(null != arg1 && arg1.equalsIgnoreCase("RSA"))) {
                throw new CertificateException("AuthType is not RSA");
            }
        }

二、破解认证

  1. 获取CA证书的KEY数据,在checkServerTrusted()方法中,把chain数组打出,保存成全局变量。
  2. 实现安全校验逻辑:
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            if (arg0 == null){
                throw new IllegalArgumentException("X509Certificate array is null");
            }
            if (!(arg0.length > 0)){
                throw new IllegalArgumentException("X509Certificate is empty");
            }
            if (!(null != arg1 && arg1.equalsIgnoreCase("RSA"))) {
                throw new CertificateException("AuthType is not RSA");
            }
            RSAPublicKey keys = (RSAPublicKey) arg0[0].getPublicKey();
            String encode = new BigInteger(1,keys.getEncoded()).toString(16);
            boolean expected = PUBLIC_KEY.equalsIgnoreCase(encode);
            if (!expected){
                throw new CertificateException("Certificate not valid or trusted.");
            }
        }

重新打包提交,基本上可以PASS了,且保证不影响原来的逻辑,当然要是对方的CA证书更换或修改,那又得重新读取Key数据。

对于有效CA,却通不过的问题,不在此讨论范围内。