https双向校验拉升通信安全性

 APP和服务器的安全十分重要,服务器端https证书可以防止钓鱼网站假冒服务器和客户端通信,盗取用户帐号信息和骗财。客户端https证书可以防止别人假冒客户端破解服务器端通信协议,盗取服务器端数据,比如爬虫就十分讨厌。双向验证,如果再对通信的核心字段使用RSA或者DES/AES加密,就可以保证APP和服务足够安全,并能防御各种代理攻击。

package com.xxx.api;

import android.content.Context;

import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.KeyManagerFactory;
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;

import okio.Buffer;

/**
 * Created by jiazhiguo([email protected]) on 2018/5/29.
 */

public class SslSocketFactoryHelp {
    /**
     * 1.双向验证客户端包括两个证书,一个是客户端私钥,一个是服务器端公钥,服务器端也有两个证书,
     * 一个是服务器私钥,一个是客户端公钥
     * 2.客户端私钥服务器用来验证客户端合法性,客户端公钥用来验证服务器合法性,
     * 3.客户端严格的双向两个证书都不可少,但客户端对于服务器的验证取决于客户端,理论上可以跳过或者全部信任,
     * 这时只需要发送客户端私有证书加密数据供服务检验即可。
     * 4.服务器端严格的双向同样是两个证书都不可少,但公共服务器一般不对客户端证书做严格校验,可以支持
     * 客户端使用X509TrustManager空证书或者默认证书请求服务,如开放的HTTPS网站,此时https只用来让客户端检测
     * 服务器是否假冒的钓鱼网站,这里是严格双向校验,有单向检验接口
     */

    /**
     * 请求地址
     */
    public static final String NEW_ROOT = "https://xxx.xxx.com";
    /**
     * 备用请求地址
     */
    public static final String NEW_ROOT_BAK = "https://xxx01.xxx.com";
    /**
     * 服务器信任库公钥证书类型,android只支持BKS,java支持jKS,cer等
     */
    public static final String KEY_STORE_TRUST_TYPE_BKS = "BKS";
    /**
     * 客户端证书类型,android支持PKCS12,java支持jKS,cer,p12等
     */
    public static final String KEY_STORE_CLIENT_TYPE_P12 = "PKCS12";
    /**
     * 客户端要给服务器端认证的证书位置,也即私有证书位置,服务器通过该证书对客户端鉴权assets
     */
    public static final String KEY_STORE_CLIENT_PATH = "xxxx.png"; 
    /**
     * 客户端验证服务器端的证书库位置,也即公有证书位置,客户端通过该证书对服务器端是否假冒检测assets
     */
    public static final String KEY_STORE_TRUST_PATH = "server.bks";
    /**
     * 客户端证书密码
     */
    public static final String KEY_STORE_PASSWORD = "xxxxxx";
    /**
     * 服务器端证书库密码,可以为空
     */
    public static final String KEY_STORE_TRUST_PASSWORD = "xxxxx";
    /**
     * 客户端要给服务器端认证的证书位置,也即私有证书位置,服务器通过该证书对客户端鉴权assets
     */
    public static final int KEY_STORE_RAW_CLIENT_PATH = R.raw.toc_picture;
    /**
     * 客户端验证服务器端的证书库位置,也即公有证书位置,客户端通过该证书对服务器端是否假冒检测assets
     */
    public static final int KEY_STORE_RAW_TRUST_PATH = R.raw.server;

    /**
     * 服务器端证书编码
     */
    public static final String TRUST_BKS = "-----BEGIN CERTIFICATE-----\n" +
            "LnpodWlzaHVzaGVucWkuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2AODF0y\n" +
            "cVVecUVavn6XDDQ7wimgzNlI7Td5vG7Ka/qs5cR/zGxNbLuPdGYVff2m0I2v4bL/TOJtmLuxXFJX\n" +
            "6jU9x8yQAnPCF4eec3Skvih+riR/omtlA3+W6sYZkehad8x9ESQ5LQ6674re4eccFpyrf17XrFpV\n" +
            "AwIrxsdm47F4m5MHugdXEehtKeQxpDEgku7TGrkeMkLcCysfioSLwGisd5NKlrxDIGKybfvtFf5n\n" +
            "ARQEjQLVswdMIqKQ2wAeEnxSF2WEbgZdkQSbn1S7PU/kprNJ+sWJdwfbPUn2Rc3/pKc4qNIRhDUY\n" +
            
            "JlAY/gmgwl6iWgzGyURHmqaTTDEYmdVY8ODNHf/tPQdoFXz99O0FuPbUmpX8ELnTnjVpGQCkMfQJ\n" +
            "reOQcTGPy8U16ZA+jk36MMtL5sY=\n" +
            "-----END CERTIFICATE-----";

    /**
     * 默认服务器端证书,用于不需要对服务器端验证的情况
     *
     * @return 服务器端证书
     */
    private static TrustManager loadtrustAllCertsManage() {
        TrustManager trustAllCerts = new X509TrustManager() {
            @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 {

            }

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

        };
        return trustAllCerts;
    }

    /**
     * 通过证书编码生成证书书
     *
     * @param trustStore_utf8 服务器端证书BASE64编码
     * @return 服务器端证书
     */
    private static KeyStore loadByteTrustStore(String trustStore_utf8) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            KeyStore TrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            TrustStore.load(null, null);
            TrustStore.setCertificateEntry("ca", cf.generateCertificate(
                    new Buffer().writeUtf8(trustStore_utf8)
                            .inputStream()));

            return TrustStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加载raw资源类服务器端证书
     *
     * @param context         上下文
     * @param truststore_type 证书类型
     * @param truststore_id   证书名字
     * @param trust_pswd      证书密码
     * @return
     */
    private static KeyStore loadTrustStore(Context context, String truststore_type, int truststore_id, String trust_pswd) {
        try {
            KeyStore localTrustStore = KeyStore.getInstance(truststore_type);
            InputStream in = context.getResources().openRawResource(truststore_id);
            ;
            try {
                localTrustStore.load(in, trust_pswd.toCharArray());
            } finally {
                in.close();
            }

            return localTrustStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加载asserts资源类服务器证书
     * @param context           上下文
     * @param truststore_type   证书类型,p12, bks,jks,cer等
     * @param truststore_assets assets资源的证书名字
     * @param trust_pswd        证书密码
     * @return
     */
    private static KeyStore loadAssetsTrustStore(Context context, String truststore_type, String truststore_assets, String trust_pswd) {
        try {
            KeyStore localTrustStore = KeyStore.getInstance(truststore_type);
            InputStream in = context.getResources().getAssets().open(truststore_assets);
            ;
            try {
                localTrustStore.load(in, trust_pswd.toCharArray());
            } finally {
                in.close();
            }

            return localTrustStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加载本地证书
     * @param context         上下文
     * @param keystore_type   证书类型,p12, bks,jks,cer等
     * @param keystore_raw_id raw资源的证书资源ID
     * @param keystore_pswd   证书密码
     * @return
     */
    private static KeyStore loadKeyStore(Context context, String keystore_type, int keystore_raw_id, String keystore_pswd) {
        try {
            KeyStore keyStore = null;
            keyStore = KeyStore.getInstance(keystore_type);
            InputStream in = context.getResources().openRawResource(keystore_raw_id);
            try {
                keyStore.load(in, keystore_pswd.toCharArray());
            } finally {
                in.close();
            }

            return keyStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加载asserts类型客户端证书
     * @param context         上下文
     * @param keystore_type   证书类型,p12, bks,jks,cer等
     * @param keystore_raw_id raw资源的证书资源ID
     * @param keystore_pswd   证书密码
     * @return
     */
    private static KeyStore loadAssetsKeyStore(Context context, String keystore_type, String keystore_raw_id, String keystore_pswd) {
        KeyStore keyStore = null;
        try {
            keyStore = KeyStore.getInstance(keystore_type);
            InputStream in = context.getResources().getAssets().open(keystore_raw_id);
            try {
                keyStore.load(in, keystore_pswd.toCharArray());
            } finally {
                in.close();
            }

            return keyStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过服务器端证书keystore和客户端证书truststore生成SSLContext
     *
     * @param keyStore   客户端证书
     * @param trustStore 服务器端证书
     * @param key_pswd   客户端证书密码
     * @return SSLContext
     * @throws GeneralSecurityException
     */
    private static SSLContext createSslContext(KeyStore keyStore, KeyStore trustStore, String key_pswd)
            throws GeneralSecurityException {

        TrustManager tms = new MyTrustManager(trustStore);

        KeyManagerFactory kmf = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, key_pswd.toCharArray());

        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(kmf.getKeyManagers(), new TrustManager[]{tms}, new SecureRandom());

        return sslcontext;
    }


    /**
     * 通过证书信息生成SSLContext
     *
     * @param context         上下语言
     * @param keystore_type   证书类型,p12, bks,jks,cer等
     * @param keystore_raw_id 客户端raw资源的证书资源ID
     * @param keystore_pswd   客户端证书密码
     * @param truststore_type 服务器端证书类型bks等
     * @param truststore_id   服务器端raw资源的证书资源ID
     * @param trust_pswd      服务器端证书密码
     * @return SSLContext
     * @throws GeneralSecurityException
     */
    private static SSLContext createSslContext(Context context, String keystore_type, int keystore_raw_id, String keystore_pswd,
                                               String truststore_type, int truststore_id, String trust_pswd)
            throws GeneralSecurityException {
        KeyStore trustStore = loadTrustStore(context, keystore_type, truststore_id, trust_pswd);
        KeyStore keyStore = loadKeyStore(context, truststore_type, keystore_raw_id, keystore_pswd);

        return createSslContext(keyStore, trustStore, keystore_pswd);
    }

    /**
     * 通过客户端证书消息和服务器端证书的BASE64信息生成SSLContext
     *
     * @param context         上下文
     * @param keystore_type   证书类型,p12, bks,jks,cer等
     * @param keystore_raw_id 客户端raw资源的证书资源ID
     * @param keystore_pswd   客户端证书密码
     * @param trust_utf8      服务器端
     * @return
     * @throws GeneralSecurityException
     */
    private static SSLContext createSslContext(Context context, String keystore_type, int keystore_raw_id, String keystore_pswd,
                                               String trust_utf8)
            throws GeneralSecurityException {
        KeyStore trustStore = loadByteTrustStore(trust_utf8);
        KeyStore keyStore = loadKeyStore(context, keystore_type, keystore_raw_id, keystore_pswd);

        return createSslContext(keyStore, trustStore, keystore_pswd);
    }

    /**
     * 通过客户羰证书和空trust证书生成SSLContext
     *
     * @param context         上下文
     * @param keystore_type   证书类型,p12, bks,jks,cer等
     * @param keystore_raw_id 客户端raw资源的证书资源ID
     * @param keystore_pswd   客户端证书密码
     * @return
     * @throws GeneralSecurityException
     */
    private static SSLContext createSslContext(Context context, String keystore_type, int keystore_raw_id, String keystore_pswd)
            throws GeneralSecurityException {
        TrustManager tms = loadtrustAllCertsManage();

        KeyStore keyStore = loadKeyStore(context, keystore_type, keystore_raw_id, keystore_pswd);
        KeyManagerFactory kmf = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, keystore_pswd.toCharArray());

        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(kmf.getKeyManagers(), new TrustManager[]{tms}, new SecureRandom());

        return sslcontext;
    }

    /**
     * 通过客户端和服务器端证书信息生成SSLSocketFactory
     *
     * @param context 上下文
     * @return SSLSocketFactory
     * @throws GeneralSecurityException
     */
    public static SSLSocketFactory getSSLSocketFactory(Context context) throws GeneralSecurityException {
        return createSslContext(context, KEY_STORE_CLIENT_TYPE_P12, KEY_STORE_RAW_CLIENT_PATH, KEY_STORE_PASSWORD,
                KEY_STORE_TRUST_TYPE_BKS, KEY_STORE_RAW_TRUST_PATH, KEY_STORE_TRUST_PASSWORD).getSocketFactory();
    }

    /**
     * 通过服务器端base64和客户端证书信息生成SSLSocketFactory
     *
     * @param context 上下文
     * @return SSLSocketFactory
     * @throws GeneralSecurityException
     */
    public static SSLSocketFactory getUtf8SSLSocketFactory(Context context) throws GeneralSecurityException {
        return createSslContext(context, KEY_STORE_CLIENT_TYPE_P12, KEY_STORE_RAW_CLIENT_PATH, KEY_STORE_PASSWORD,
                TRUST_BKS).getSocketFactory();

    }

    /**
     * 生成对服务器端免除验证的SSLSocketFactory
     *
     * @param context 上下文
     * @return SSLSocketFactory
     * @throws GeneralSecurityException
     */
    public static SSLSocketFactory getTrustAllSSLSocketFactory(Context context) throws GeneralSecurityException {
        return createSslContext(context, KEY_STORE_CLIENT_TYPE_P12, KEY_STORE_RAW_CLIENT_PATH, KEY_STORE_PASSWORD)
                .getSocketFactory();
    }

    /**
     * 服务器端证书类
     */
    public static class MyTrustManager implements X509TrustManager {
        /**
         * 服务器证书
         */
        class LocalStoreX509TrustManager implements X509TrustManager {

            private X509TrustManager trustManager;

            LocalStoreX509TrustManager(KeyStore localTrustStore) {
                try {
                    TrustManagerFactory tmf = TrustManagerFactory
                            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    tmf.init(localTrustStore);

                    trustManager = findX509TrustManager(tmf);
                    if (trustManager == null) {
                        throw new IllegalStateException(
                                "Couldn't find X509TrustManager");
                    }
                } catch (GeneralSecurityException e) {
                    throw new RuntimeException(e);
                }

            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                trustManager.checkClientTrusted(chain, authType);
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                trustManager.checkServerTrusted(chain, authType);
            }

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

        /**
         * 系统默认证书
         */
        static X509TrustManager findX509TrustManager(TrustManagerFactory tmf) {
            TrustManager tms[] = tmf.getTrustManagers();
            for (int i = 0; i < tms.length; i++) {
                if (tms[i] instanceof X509TrustManager) {
                    return (X509TrustManager) tms[i];
                }
            }

            return null;
        }

        private X509TrustManager defaultTrustManager;
        private X509TrustManager localTrustManager;

        private X509Certificate[] acceptedIssuers;

        /**
         * 使用系统默认证书,失败时使用添加的证书
         *
         * @param localKeyStore
         */
        private MyTrustManager(KeyStore localKeyStore) {
            try {
                TrustManagerFactory tmf = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init((KeyStore) null);

                defaultTrustManager = findX509TrustManager(tmf);
                if (defaultTrustManager == null) {
                    throw new IllegalStateException(
                            "Couldn't find X509TrustManager");
                }

                localTrustManager = new MyTrustManager.LocalStoreX509TrustManager(localKeyStore);

                List<X509Certificate> allIssuers = new ArrayList<X509Certificate>();
                for (X509Certificate cert : defaultTrustManager
                        .getAcceptedIssuers()) {
                    allIssuers.add(cert);
                }
                for (X509Certificate cert : localTrustManager.getAcceptedIssuers()) {
                    allIssuers.add(cert);
                }
                acceptedIssuers = allIssuers.toArray(new X509Certificate[allIssuers
                        .size()]);
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            }


        }

        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            try {
                defaultTrustManager.checkClientTrusted(chain, authType);
            } catch (CertificateException ce) {
                localTrustManager.checkClientTrusted(chain, authType);
            }
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException ce) {
                localTrustManager.checkServerTrusted(chain, authType);
            }
        }

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

    }
}

猜你喜欢

转载自blog.csdn.net/blogercn/article/details/82145888