安卓App漏洞扫描问题记录

1、场景

项目进行等保测试,App扫描出了几项漏洞需要修复:

2、问题分析

根据描述给的建议,应该还是项目使用了https环境部署,App中有访问后台接口,但是客户端没有对服务端证书进行完整性校验暴露出的问题。App中主要是使用okhttp 框架进行接口访问,对应证书校验这块确实没有实现。

3、问题处理

参考Android App 安全的HTTPS 通信 - 简书 文章, 其实主要应该就是在代码中设置对应的校验逻辑即可:

自定义的逻辑:

try {
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // uwca.crt 打包在 asset 中,该证书可以从https://itconnect.uw.edu/security/securing-computer/install/safari-os-x/下载
    InputStream caInput = new BufferedInputStream(mContext.getAssets().open("xxx.cer"));
    Certificate ca;
    try {
        ca = cf.generateCertificate(caInput);
        Log.i("Longer", "ca=" + ((X509Certificate) ca).getSubjectDN());
        Log.i("Longer", "key=" + ((X509Certificate) ca).getPublicKey());
    } finally {
        caInput.close();
    }

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLSv1","AndroidOpenSSL");
    context.init(null, tmf.getTrustManagers(), null);

    HostnameVerifier hnv = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            //示例
            if("yourhostname".equals(hostname)){
                return true;
            } else {
                HostnameVerifier hv =
                        HttpsURLConnection.getDefaultHostnameVerifier();
                boolean verify =  hv.verify(hostname, session);
                System.out.println("=====verify="+verify);
                return verify;
            }
        }
    };



    URL url = new URL("https://xxx.com/");
    HttpsURLConnection urlConnection =
            (HttpsURLConnection)url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());
    urlConnection.setHostnameVerifier(hnv);
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);

    //使用okhttp 来访问
    Request request = new Request.Builder().url("https://xxx..com/").get().build();
    // 获取X509TrustManager
    X509TrustManager x509TrustManager = null;
    for (javax.net.ssl.TrustManager tm : tmf.getTrustManagers()) {
        if (tm instanceof X509TrustManager) {
            x509TrustManager = (X509TrustManager)tm;
        }
    }
    OkHttpClient   okHttpClient = new OkHttpClient();
    okHttpClient.newBuilder().sslSocketFactory(context.getSocketFactory(), x509TrustManager)
            .hostnameVerifier(hnv);
    Call call= okHttpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            System.out.println("response is "+response.body());
        }
    });


} catch (CertificateException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (KeyStoreException e) {
    e.printStackTrace();
} catch (KeyManagementException e) {
    e.printStackTrace();
} catch (NoSuchProviderException e) {
    e.printStackTrace();
}

其中打包到App中的这个证书,不要使用后台服务器上的pem 公钥证书,而是要使用CA 根证书,不然依然会报错:

 

在调试完之后,我发现自己的代码接口中都是使用了默认的OKHttp 接口访问方式,并没有进行特殊设置自定义的,这种默认的设置都是会进行校验的,理论上说不存在这种漏洞,后面发现代码中有一个没有使用的类:

package com.hnac.utils;


import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class SSLSocketClient {

    //获取这个SSLSocketFactory
    public static SSLSocketFactory getSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, getTrustManager(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //获取TrustManager
    private static TrustManager[] getTrustManager() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }

    //获取HostnameVerifier
    public static HostnameVerifier getHostnameVerifier() {
        return (s, sslSession) -> true;
    }

    public static X509TrustManager getX509TrustManager() {
        X509TrustManager trustManager = null;
        try {
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init((KeyStore) null);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            trustManager = (X509TrustManager) trustManagers[0];
        } catch (Exception e) {
            e.printStackTrace();
        }

        return trustManager;
    }

}

 

这个应该是之前为了解决每次证书校验报错,找到的一个直接信任所有,不进行证书校验而增加的,代码虽然没用,但是可以漏洞扫描工具扫到这个问题,所以这个问题估计删除掉这个就可以解决了,等待后续验证。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值