【漏洞修复】自定义实现的X509TrustManager子类中..

漏洞说明

 /**
     * 覆盖java默认的证书验证
     */
    private static final TrustManager[] TRUSTALLCERTS = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[]{};
                }

                @SuppressLint("TrustAllX509TrustManager")
                public void checkClientTrusted(X509Certificate[] chain, String authType) {
                }

                @SuppressLint("TrustAllX509TrustManager")
                public void checkServerTrusted(X509Certificate[] chain, String authType) {
                }
            }
    };

 try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, TRUSTALLCERTS, new java.security.SecureRandom()); //配置自己的信任管理类(信任策略)
            SSLSocketFactory newFactory = sc.getSocketFactory();
            connection.setSSLSocketFactory(newFactory);
        } catch (Exception e) {
            e.printStackTrace();
        }

如上代码所示,自定义与使用了X509TrustManager子类,但又没有实现信任校验的逻辑时遇,对安全平台扫描APK时,会报如下风险

【漏洞】自定义实现的X509TrustManager子类中,未对服务器端证书做验证,默认接受任意服务端证书,会存在安全风险,可能会导致恶意程序利用中间人攻击绕过证书校验

【修复的建议通常的如下】

利用X509TrustManager子类中的checkServerTrusted函数,校验服务器端证书的合法性

PS:一般自定义信任管理器,通常是使用自签名或android不认可的证书颁发机构SSL证书的业务场景
使用这个方式最麻烦是公钥/证书放置在前端,以及公钥的同步等问题!!!

修复建议

个人的修复建议是
【前提条件】
1、你的SSL证书是由android认可的证书颁发机构或者该结构下属的机构颁发的证书(最关键)
2、使用的https的服务的请求与响应的数据安全性不是那么高(数据不敏感与私密),
3、又不保证服务器的证书是否不会被替换,
那么性价较高且简单明了的方案是

不要使用509TrustManager子类!
不要使用509TrustManager子类!
不要使用509TrustManager子类!
即使用默认的系统网络库默认的信任管理/校验方案,系统会使用证书链的信任管理策略

PS:

Android已经把将近150个CA根证书(数字证书认证机构认证过的证书)内置在我们手机中。这150多个证书被全世界信赖

TIPS分享

查看域名的证书的信息

利用chrome打开对应的域名,查看即可
【漏洞修复】自定义实现的X509TrustManager子类中.._第1张图片
证书详情
【漏洞修复】自定义实现的X509TrustManager子类中.._第2张图片

查看信息的信证CA根证书

设置->安全->信任的凭据
【漏洞修复】自定义实现的X509TrustManager子类中.._第3张图片

自定义X509TrustManage示例

说明 : 如下代码copy自 学会正确的使用 https,不要留下漏洞!!

public static SSLSocketFactory getSSLSocketFactory() throws Exception {
        
        final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            // 本地公钥信息,实现项目中在考虑该值的更新,否则服务证书一换,之前的端不会能正常工作了
            public static final String PUB_KEY = "3082010a0282010100d52ff5dd432b3a05113ec1a7065fa5a80308810e4e181cf14f7598c8d553cccb7d5111fdcdb55f6ee84fc92cd594adc1245a9c4cd41cbe407a919c5b4d4a37a012f8834df8cfe947c490464602fc05c18960374198336ba1c2e56d2e984bdfb8683610520e417a1a9a5053a10457355cf45878612f04bb134e3d670cf96c6e598fd0c693308fe3d084a0a91692bbd9722f05852f507d910b782db4ab13a92a7df814ee4304dccdad1b766bb671b6f8de578b7f27e76a2000d8d9e6b429d4fef8ffaa4e8037e167a2ce48752f1435f08923ed7e2dafef52ff30fef9ab66fdb556a82b257443ba30a93fda7a0af20418aa0b45403a2f829ea6e4b8ddbb9987f1bf0203010001";

            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {


            }

            
            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
                if (chain == null) {
                    throw new IllegalArgumentException("checkServerTrusted:x509Certificate array isnull");
                }

                if (!(chain.length > 0)) {
                    throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty");
                }

                if (!(null != authType && authType.equalsIgnoreCase("RSA"))) {
                    throw new CertificateException("checkServerTrusted: AuthType is not RSA");
                }

                
                try {
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
                    tmf.init((KeyStore) null);
                    for (TrustManager trustManager : tmf.getTrustManagers()) {
                        ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
                    }
                } catch (Exception e) {
                    throw new CertificateException(e);
                }
                
                
                RSAPublicKey pubkey = (RSAPublicKey) chain[0].getPublicKey();

                String encoded = new BigInteger(1 , pubkey.getEncoded()).toString(16);
                
                final boolean expected = PUB_KEY.equalsIgnoreCase(encoded);

                if (!expected) {
                    throw new CertificateException("checkServerTrusted: Expected public key: "
                            + PUB_KEY + ", got public key:" + encoded);
                }

            }


            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};

        
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts,
                new java.security.SecureRandom());
        
        return sslContext
                .getSocketFactory();
    }

相关文档

  • 学会正确的使用 https,不要留下漏洞!!
  • https是如何工作的?
  • 聊聊 Android HTTPS 的使用姿势
  • 学会正确的使用 https,不要留下漏洞!!
  • Https证书校验不当引起的安全问题
  • 通过 HTTPS 和 SSL 确保安全

你可能感兴趣的:(Android开发之旅,android,X509)