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


From: http://my.oschina.net/jjface/blog/339144

概述: 客戶端,瀏覽器或者使用http協議和服務器通信的程序。 如: 客戶端通過瀏覽器訪問某一網站時,如果該網站為HTTPS網站,瀏覽器會自動檢測系統中是否存在該網站的信任證書, 如果沒有信任證書,瀏覽器一般會拒絕訪問,IE會有一個繼續訪問的鏈接,但地址欄是紅色,給予用戶警示作用, 即客戶端驗證服務端並不是強制性的,可以沒有服務端的信任證書,當然是否繼續訪問完全取決於用戶自己。 如果要去除地址欄的紅色警告,需要導入服務端提供的證書到瀏覽器中。 服務器端,使用http協議提供服務的程序。 服務端需要獲取到客戶端通過瀏覽器發送過來的認證證書, 如: 該證書在服務端的證書庫中已存在,僅僅是個...

 

概述:
客戶端,瀏覽器或者使用http協議和服務器通信的程序。
如:
客戶端通過瀏覽器訪問某一網站時,如果該網站為HTTPS網站,瀏覽器會自動檢測系統中是否存在該網站的信任證書,
如果沒有信任證書,瀏覽器一般會拒絕訪問,IE會有一個繼續訪問的鏈接,但地址欄是紅色,給予用戶警示作用,
即客戶端驗證服務端並不是強制性的,可以沒有服務端的信任證書,當然是否繼續訪問完全取決於用戶自己。
如果要去除地址欄的紅色警告,需要導入服務端提供的證書到瀏覽器中。

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

基本邏輯:
1、生成服務端密鑰庫並導出證書.
2、生成客戶端密鑰庫並導出證書.
3、根據服務端密鑰庫生成客戶端信任的證書.
4、將客戶端證書導入服務端密鑰庫.
5、將服務端證書導入瀏覽器.

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


生成密鑰庫和證書:
因使用java環境,下面使用jdk下面的keytool工具來生成相應的密鑰庫和證書
下面的命令是在windows 7 下面測試通過的,可以直接復制使用
1、創建目錄,如d:/sslDemo

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

3、服務器端相關操作
3.1、生成服務器證書庫
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.2、從服務器證書庫中導出服務器證書
keytool -export -v -alias server -keystore server.keystore -storepass 123456 -rfc -file server.cer

3.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、客戶端相關操作
4.1、生成客戶端證書庫
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.2、從客戶端證書庫中導出客戶端證書
keytool -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass 123456 -rfc -file client.cer

注:客戶端證書可以產生多個.

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

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

5、服務器端配置
由於使用tomcat,下面使用tomcat做為實例配置.
5.1、在tomcat安裝目錄下新建key目錄,將上面生成的server.keystore復制過去.
5.2、編輯tomcat安裝目錄下的conf目錄下的server.xml,如:d:\sslDemo\apache-tomcat-7.0.55\conf\server.xml
找到Connector,修改如下:

?
1
2
3
4
5
6
7
< 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" 服務器證書庫(已導入客戶端證書)

6、測試
由於生成證書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/
此時會有證書相關的提示,點擊"確認",接着會提示網站安全證書有問題,點擊繼續訪問,即可進入正常訪問頁面

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

?
1
2
3
4
5
6
7
8
9
< 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地址,驗證才可以通過

1、android app 代碼實現

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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;
     }
}

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM