Android HTTPS SSL雙向驗證 使用HTTPs

HTTPS和HTTP的區別html

一、https協議須要到ca申請證書,通常免費證書不多,須要交費。

二、http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。

三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。

四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

2、SSL功能

1)客戶對服務器的身份認證:
SSL服務器容許客戶的瀏覽器使用標準的公鑰加密技術和一些可靠的認證中心(CA)的證書,來確認服務器的合法性。

2)服務器對客戶的身份認證:
也可經過公鑰技術和證書進行認證,也可經過用戶名,password來認證。

3)創建服務器與客戶之間安全的數據通道:
SSL要求客戶與服務器之間的全部發送的數據都被髮送端加密、接收端解密,同時還檢查數據的完整性。

SSL協議位於TCP/IP協議與各類應用層協議之間,爲數據通信提供安全支持。SSL協議可分爲兩層:java

SSL記錄協議(SSL Record Protocol):它創建在可靠的傳輸協議(如TCP)之上,爲高層協議提供數據封裝、壓縮、加密等基本功能的支持。android

SSL握手協議(SSL Handshake Protocol):它創建在SSL記錄協議之上,用於在實際的數據傳輸開始前,通信雙方進行身份認證、協商加密算法、交換加密密鑰等。算法

3、生成密鑰庫和證書

可參考如下密鑰生成腳本,根據實際狀況作必要的修改,其中須要注意的是:服務端的密鑰庫參數「CN」必須與服務端的IP地址相同,不然會報錯,客戶端的任意。瀏覽器

一、生成服務器證書庫

keytool -validity 365 -genkey -v -alias server -keyalg RSA -keystore D:\ssl\server.keystore -dname "CN=127.0.0.1,OU=rongyiwang,O=rongyiwang,L=Shanghai,ST=Shanghai,c=cn" -storepass 123456 -keypass 123456

二、生成客戶端證書庫

keytool -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore D:\ssl\client.p12 -dname "CN=client,OU=rongyiwang,O=rongyiwang,L=Shanghai,ST=Shanghai,c=cn" -storepass 123456 -keypass 123456

三、從客戶端證書庫中導出客戶端證書

keytool -export -v -alias client -keystore D:\ssl\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\ssl\client.cer

四、從服務器證書庫中導出服務器證書

keytool -export -v -alias server -keystore D:\ssl\server.keystore -storepass 123456 -rfc -file D:\ssl\server.cer

五、生成客戶端信任證書庫(由服務端證書生成的證書庫)

keytool -import -v -alias server -file D:\ssl\server.cer -keystore D:\ssl\client.truststore -storepass 123456

六、將客戶端證書導入到服務器證書庫(使得服務器信任客戶端證書)

keytool -import -v -alias client -file D:\ssl\client.cer -keystore D:\ssl\server.keystore -storepass 123456

七、查看證書庫中的所有證書

keytool -list -keystore D:\ssl\server.keystore -storepass 123456

經過上面的步驟生成的證書,客戶端須要用到的是client.p12(客戶端證書,用於請求的時候給服務器來驗證身份之用)和client.truststore(客戶端證書庫,用於驗證服務器端身份,防止釣魚)這兩個文件.
安全

其中安卓端的證書類型必需要求是BKS類型,具體生成能夠參考這個create a bks bouncycastle,這裏涉及到這個JARbcprov-ext-jdk15on-152.jar文件.服務器

如下只給出Android端的請求,具體服務器端的配置能夠參考這篇博客-->Java Tomcat SSL 服務端/客戶端雙向認證(一)網絡


4、Android端SSL認證請求

        通常客戶端驗證SSL有兩種方式,一種是經過SSLSocketFactory方式建立,須要設置域名及端口號(適應於HttpClient請求方式),一種是經過SSLContext方式建立(適用於HttpsURLConnection請求方式).
一、下面給出SslSocketFactory方式進行SSL認證的客戶端代碼數據結構

private static final String KEY_STORE_TYPE_BKS = "bks";//證書類型 固定值
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";//證書類型 固定值

    private static final String KEY_STORE_CLIENT_PATH = "client.p12";//客戶端要給服務器端認證的證書
    private static final String KEY_STORE_TRUST_PATH = "client.truststore";//客戶端驗證服務器端的證書庫
    private static final String KEY_STORE_PASSWORD = "123456";// 客戶端證書密碼
    private static final String KEY_STORE_TRUST_PASSWORD = "123456";//客戶端證書庫密碼

    /**
     * 獲取SslSocketFactory
     *
     * @param context 上下文
     * @return SSLSocketFactory
     */
    public static SSLSocketFactory getSslSocketFactory(Context context) {
        try {
            // 服務器端須要驗證的客戶端證書
            KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            // 客戶端信任的服務器端證書
            KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);

            InputStream ksIn = context.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
            InputStream tsIn = context.getResources().getAssets().open(KEY_STORE_TRUST_PATH);
            try {
                keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
                trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    ksIn.close();
                } catch (Exception ignore) {
                }
                try {
                    tsIn.close();
                } catch (Exception ignore) {
                }
            }
            return new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
        } catch (KeyManagementException | UnrecoverableKeyException | KeyStoreException | FileNotFoundException | NoSuchAlgorithmException | ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 獲取SSL認證須要的HttpClient
     *
     * @param context 上下文
     * @param port    端口號
     * @return HttpClient
     */
    public static HttpClient getSslSocketFactoryHttp(Context context, int port) {
        HttpClient httpsClient = new DefaultHttpClient();
        SSLSocketFactory sslSocketFactory = getSslSocketFactory(context);
        if (sslSocketFactory != null) {
            Scheme sch = new Scheme("https", sslSocketFactory, port);
            httpsClient.getConnectionManager().getSchemeRegistry().register(sch);
        }
        return httpsClient;
    }

二、下面給出SSLContext方式進行SSL認證的客戶端代碼ide

private static final String KEY_STORE_TYPE_BKS = "bks";//證書類型 固定值
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";//證書類型 固定值

    private static final String KEY_STORE_CLIENT_PATH = "client.p12";//客戶端要給服務器端認證的證書
    private static final String KEY_STORE_TRUST_PATH = "client.truststore";//客戶端驗證服務器端的證書庫
    private static final String KEY_STORE_PASSWORD = "123456";// 客戶端證書密碼
    private static final String KEY_STORE_TRUST_PASSWORD = "123456";//客戶端證書庫密碼
    
    /**     * 獲取SSLContext     *     * @param context 上下文     * @return SSLContext     */
    private static SSLContext getSSLContext(Context context) {
        try {
            // 服務器端須要驗證的客戶端證書
            KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            // 客戶端信任的服務器端證書
            KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);

            InputStream ksIn = context.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
            InputStream tsIn = context.getResources().getAssets().open(KEY_STORE_TRUST_PATH);
            try {
                keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
                trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    ksIn.close();
                } catch (Exception ignore) {
                }
                try {
                    tsIn.close();
                } catch (Exception ignore) {
                }
            }
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
            keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
            return sslContext;
        } catch (Exception e) {
            Log.e("tag", e.getMessage(), e);
        }
        return null;
    }
    
    /**     * 獲取SSL認證須要的HttpClient     *     * @param context 上下文     * @return OkHttpClient     */
    public static OkHttpClient getSSLContextHttp(Context context) {
        OkHttpClient client = new OkHttpClient();
        SSLContext sslContext = getSSLContext(context);
        if (sslContext != null) {
            client.setSslSocketFactory(sslContext.getSocketFactory());
        }
        return client;
    }
    
    /**     * 獲取HttpsURLConnection     *     * @param context 上下文     * @param url     鏈接url     * @param method  請求方式     * @return HttpsURLConnection     */
    public static HttpsURLConnection getHttpsURLConnection(Context context, String url, String method) {
        URL u;
        HttpsURLConnection connection = null;
        try {
            SSLContext sslContext = getSSLContext(context);
            if (sslContext != null) {
                u = new URL(url);
                connection = (HttpsURLConnection) u.openConnection();
                connection.setRequestMethod(method);//"POST" "GET"
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setUseCaches(false);
                connection.setRequestProperty("Content-Type", "binary/octet-stream");
                connection.setSSLSocketFactory(sslContext.getSocketFactory());
                connection.setConnectTimeout(30000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }

參考:http://blog.csdn.net/u012874222/article/details/50339259


//使用https傳輸:

參考:http://blog.csdn.net/haoaoo/article/details/54614875

http://blog.csdn.net/dlx2chengyt/article/details/53081329

相關文章
相關標籤/搜索