App校验https证书

对App进行全面的安全性测试的时候,发现虽然用的https证书,但是也同时开启了允许任意http链接,导致检测的时候提示不安全

  1. 安卓HttpsURLConnection使用证书

    //HttpsURLConnection
    private static void setCertificate(HttpsURLConnection connection) {
        InputStream caInput = null;
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            caInput = MyApplication.mContext.getAssets().open("sguClass.cer");
            Certificate ca = cf.generateCertificate(caInput);
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
    
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
            connection.setSSLSocketFactory(context.getSocketFactory());
            connection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
        } catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        } finally {
            try {
                caInput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  2. 安卓WebView使用证书

            //Webview
            public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
    //            super.onReceivedSslError(webView, sslErrorHandler, sslError);//sslErrorHandler.cancel();
    //            sslErrorHandler.proceed();
    
                if (chkMySSLCNCert(sslError.getCertificate())) {{//结果应该都是false,有问题的话取消验证
                    sslErrorHandler.proceed();
                } else {
                    sslErrorHandler.cancel();
                }
    
    //            if (sslError.getPrimaryError() == android.net.http.SslError.SSL_DATE_INVALID  // 日期不正确
    //                    || sslError.getPrimaryError() == android.net.http.SslError.SSL_EXPIRED // 日期不正确
    //                    || sslError.getPrimaryError() == android.net.http.SslError.SSL_INVALID // webview BUG
    //                    || sslError.getPrimaryError() == android.net.http.SslError.SSL_UNTRUSTED) { // 根证书丢失
    //                if (chkMySSLCNCert(sslError.getCertificate())) {
    //                    sslErrorHandler.proceed();  // 如果证书一致,忽略错误
    //                }
    //            }
            }
        private static boolean chkMySSLCNCert(SslCertificate cert) {
            try {
                //本地证书
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                InputStream caInput = MyApplication.mContext.getAssets().open("sguClass.cer");
                Certificate ca = cf.generateCertificate(caInput);
                MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
                byte[] caKey = sha256.digest(ca.getEncoded());
    
                //服务端证书
                Bundle bundle = SslCertificate.saveState(cert);
                byte[] bytes = bundle.getByteArray("x509-certificate");
                Certificate certificate = cf.generateCertificate(new ByteArrayInputStream(bytes));;
                byte[] certificateKey = sha256.digest(certificate.getEncoded());
                Log.d("test", "chkMySSLCNCert" + "caKey:" + caKey + " certificateKey: " + certificateKey);
                return Arrays.equals(caKey, certificateKey);
            } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
    
            return false;
        }
    
  3. iOS afnetworking添加证书

    //AFNetworking
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager manager] initWithBaseURL:[NSURL URLWithString:BASE_URL_API]];
    manager.securityPolicy = [self customSecurityPolicy];
    + (AFSecurityPolicy *)customSecurityPolicy {
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"sguClass" ofType:@"cer"];//证书的路径
        NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
        securityPolicy.allowInvalidCertificates = NO;//是否允许无效证书
        if (cerData) {
            securityPolicy.pinnedCertificates = [NSSet setWithObject:cerData];
        }
        return securityPolicy;
    }
    
  4. iOS WKWebView添加证书

    //WKWebview
    //Allow Arbitrary Loads in Web Content设置为YES防止外部http链接打不开
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
        NSLog(@"didReceiveAuthenticationChallenge");
        //1.信任所有证书
    //    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
    //        NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
    //        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
    //    }
        
        //2.比较证书内容,相同的在信任 //强限制,部分部分外部资源加载不了
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        // 从信任链返回一个证书
        SecCertificateRef serverCer= SecTrustGetCertificateAtIndex(trust, 0);
        // SecCertificateCopyData 返回X.509证书的DER表示
        NSData *serverCerData = CFBridgingRelease(SecCertificateCopyData(serverCer));
        NSString *localCerPath = [[NSBundle mainBundle] pathForResource:@"sguClass" ofType:@"cer"];
        NSData *localCerData = [NSData dataWithContentsOfFile:localCerPath];
        if ([serverCerData isEqualToData:localCerData]) {
            NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:trust];
            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
            NSLog(@"服务端证书认证成功");
        } else {
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL);
            NSLog(@"服务端证书认证失败");
        }
    }
    

添加完证书之后,发现会有一些问题,主要是外部http资源和第三方http链接无法访问,所以有去掉了部分验证。如果项目没有用到这些内容,还是可以添加的,更安全一些。

posted @ 2022-03-21 21:57  yuyuyu37  阅读(366)  评论(0编辑  收藏  举报