基於java的https雙向認證,android上亦可用

概述:
客戶端,瀏覽器或者使用http協議和服務器通訊的程序。
如:
客戶端經過瀏覽器訪問某一網站時,若是該網站爲HTTPS網站,瀏覽器會自動檢測系統中是否存在該網站的信任證書,
若是沒有信任證書,瀏覽器通常會拒絕訪問,IE會有一個繼續訪問的連接,但地址欄是紅色,給予用戶警示做用,
即客戶端驗證服務端並非強制性的,能夠沒有服務端的信任證書,固然是否繼續訪問徹底取決於用戶本身。
若是要去除地址欄的紅色警告,須要導入服務端提供的證書到瀏覽器中。

服務器端,使用http協議提供服務的程序。
服務端須要獲取到客戶端經過瀏覽器發送過來的認證證書,
如:
該證書在服務端的證書庫中已存在,僅僅是個匹配過程,匹配成功即經過認證,可繼續訪問網站資源,反之則沒法顯示網頁。

基本邏輯:
一、生成服務端密鑰庫並導出證書.
二、生成客戶端密鑰庫並導出證書.
三、根據服務端密鑰庫生成客戶端信任的證書.
四、將客戶端證書導入服務端密鑰庫.
五、將服務端證書導入瀏覽器.
java

源碼下載地址:http://pan.baidu.com/s/1eQ5r9OA
android


生成密鑰庫和證書:
因使用java環境,下面使用jdk下面的keytool工具來生成相應的密鑰庫和證書
下面的命令是在windows 7 下面測試經過的,能夠直接複製使用
一、建立目錄,如d:/sslDemo

二、使用資源管理進入d:/sslDemo,按住shift+右鍵,彈出菜單,選擇"在此處打開命令行".

三、服務器端相關操做
3.一、生成服務器證書庫
keytool -validity 36500 -genkey -v -alias server -keyalg RSA -keystore server.keystore -dname "CN=www.itjoyee.com,OU=itjoyee.com,O=itjoyee.com,L=Wuhan,ST=HuBei,c=cn" -storepass 123456 -keypass 123456
注: 服務器證書庫參數「CN」必須與服務端的IP地址相同,不然會報錯,客戶端的任意。

3.二、從服務器證書庫中導出服務器證書
keytool -export -v -alias server -keystore server.keystore -storepass 123456 -rfc -file server.cer

3.三、生成客戶端信任證書庫(由服務端證書生成的證書庫,客戶端使用此證書驗證服務端來源可靠)
keytool -import -v -alias server -file server.cer -keystore client.truststore -storepass 123456 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

注:-storetype BKS 是生成android上面能夠識別的格式,若是不指定jdk默認生成的格式是JKS.
-provider org.bouncycastle.jce.provider.BouncyCastleProvider,須要下載jar包bcprov-jdk16-1.46.jar放到jdk1.7.0_65\jre\lib\ext\目錄下.
注意須要jdk16,其餘的版本android下面有版本不匹配的問題.


四、客戶端相關操做
4.一、生成客戶端證書庫
keytool -validity 36500 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore client.p12 -dname "CN=clients.itjoyee.com,OU=jiajianfa,O=jiajianfa,L=Wuhan,ST=HuBei,c=cn" -storepass 123456 -keypass 123456

4.二、從客戶端證書庫中導出客戶端證書
keytool -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass 123456 -rfc -file client.cer

注:客戶端證書能夠產生多個.

4.三、將客戶端證書導入到服務器證書庫(使得服務器信任客戶端證書,服務器端用此驗證客戶端的合法性)
keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass 123456

4.四、查看服務端證書中信任的客戶端證書
keytool -list -keystore server.keystore -storepass 123456

五、服務器端配置
因爲使用tomcat,下面使用tomcat作爲實例配置.
5.一、在tomcat安裝目錄下新建key目錄,將上面生成的server.keystore複製過去.
5.二、編輯tomcat安裝目錄下的conf目錄下的server.xml,如:d:\sslDemo\apache-tomcat-7.0.55\conf\server.xml
找到Connector,修改以下:
web

<Connector port="8444" protocol="org.apache.coyote.http11.Http11NioProtocol" 
           maxThreads="150" 
           SSLEnabled="true" scheme="https" secure="true"
           keystoreFile="${catalina.base}/key/server.keystore" keystorePass="123456"
           
           clientAuth="true" sslProtocol="TLS"
           truststoreFile="${catalina.base}/key/server.keystore" truststorePass="123456"/>

注:           
port配置https訪問的端口
SSLEnabled="true" 開啓https服務
scheme="https"
secure="true"    開啓服務端安全通訊,客戶端獲取服務器端證書
keystoreFile="${catalina.base}/key/server.keystore" keystorePass="123456" 服務器證書庫

clientAuth="true" 開啓驗證客戶端
sslProtocol="TLS" 使用的協議
truststoreFile="${catalina.base}/key/server.keystore" truststorePass="123456" 服務器證書庫(已導入客戶端證書)

六、測試
因爲生成證書CN配置的是www.itjoyee.com,故須要修改C:\Windows\System32\drivers\etc\hosts
添加

192.168.0.50    www.itjoyee.com
注:
192.168.0.50 爲服務器的ip

啓動tomcat
打開瀏覽器
地址欄輸入 http://www.itjoyee.com:8080/
能夠訪問

地址欄輸入https://www.itjoyee.com:8444/
訪問結果,爲沒法顯示,由於,沒有使服務器端生成的信任的客戶端證書

雙擊client.p12,輸入密碼,在此訪問https://www.itjoyee.com:8444/
此時會有證書相關的提示,點擊"確認",接着會提示網站安全證書有問題,點擊繼續訪問,便可進入正常訪問頁面

七、tomcat下的服務強制使用ssl配置
已ROOT服務爲例,修改D:\sslDemo\apache-tomcat-7.0.55\webapps\ROOT\WEB-INF\web.xml
添加
apache

<security-constraint>       
    <web-resource-collection>
        <web-resource-name >SSL</web-resource-name>  
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
    </user-data-constraint>
</security-constraint>

打開瀏覽器
地址欄輸入 http://www.itjoyee.com:8080/會有證書相關提示


爲了方便測試android下雙向認證能夠用,生成證書的時候把域名換成服務器的ip地址,驗證才能夠經過

一、android app 代碼實現
windows

AsyncTask testTask = new AsyncTask() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
                    HttpClient httpsClient = AppSslApplication.getHttpsClient(MainActivity.this.getBaseContext());
                    HttpGet httpget = new HttpGet(HTTPS_URL);
                    HttpResponse response = httpsClient.execute(httpget);
                    HttpEntity entity = response.getEntity();
                    Log.e("Response status", response.getStatusLine().toString());
                    if (entity != null) {
                        Log.e("Response", "Response content length: " + entity.getContentLength());
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                        String text;
                        while ((text = bufferedReader.readLine()) != null) {
                            Log.e("Response status", text);
                        }
                        bufferedReader.close();
                    }
                    httpsClient.getConnectionManager().shutdown();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        };
        testTask.execute();
public class HttpClientSslHelper {
    private static final String KEY_STORE_TYPE_BKS = "bks";
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";
    private static final String SCHEME_HTTPS = "https";
    private static final int HTTPS_PORT = 8444;
    
    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";
    private static KeyStore keyStore;
    private static KeyStore trustStore;
    public static HttpClient getSslHttpClient(Context pContext) {
        HttpClient httpsClient = new DefaultHttpClient();
        try {
            // 服務器端須要驗證的客戶端證書
            keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            
            // 客戶端信任的服務器端證書
            trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
            
            InputStream ksIn = pContext.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
            InputStream tsIn = pContext.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) {
                }
            }
            SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
            Scheme sch = new Scheme(SCHEME_HTTPS, socketFactory, HTTPS_PORT);
            httpsClient.getConnectionManager().getSchemeRegistry().register(sch);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return httpsClient;
    }
}

二、android瀏覽器實現
1.先把你的CA證書拷貝到你的SD卡里面
2.進入手機的"設置"->"位置和安全",最下面有個"從SD卡安裝",就是安裝證書的。
---------暫時沒有實現
瀏覽器

相關文章
相關標籤/搜索