stone2083

          SSL雙向認證java實現(xiàn)

          本文通過模擬場景,介紹SSL雙向認證的java實現(xiàn)

          默認的情況下,我認為讀者已經對SSL原理有一定的了解,所以文章中對SSL的原理,不做詳細的介紹。
          如果有這個需要,那么通過GOOGLE,可以搜索到很多這樣的文章。

          模擬場景:
          Server端和Client端通信,需要進行授權和身份的驗證,即Client只能接受Server的消息,Server只能接受Client的消息。

          實現(xiàn)技術:
          JSSE(Java Security Socket Extension
          是Sun為了解決在Internet上的安全通訊而推出的解決方案。它實現(xiàn)了SSL和TSL(傳輸層安全)協(xié)議。在JSSE中包含了數據加密,服務器驗證,消息完整性和客戶端驗證等技術。通過使用JSSE,開發(fā)人員可以在客戶機和服務器之間通過TCP/IP協(xié)議安全地傳輸數據

          為了實現(xiàn)消息認證。
          Server需要:
          1)KeyStore: 其中保存服務端的私鑰
          2)Trust KeyStore:其中保存客戶端的授權證書
          同樣,Client需要:
          1)KeyStore:其中保存客戶端的私鑰
          2)Trust KeyStore:其中保存服務端的授權證書

          我們可以使用Java自帶的keytool命令,去生成這樣信息文件
          1)生成服務端私鑰,并且導入到服務端KeyStore文件中
          keytool -genkey -alias serverkey -keystore kserver.keystore
          過程中,分別需要填寫,根據需求自己設置就行
          keystore密碼:123456
          名字和姓氏:stone
          組織單位名稱:eulic
          組織名稱:eulic
          城市或區(qū)域名稱:HZ
          州或省份名稱:ZJ
          國家代碼:CN
          serverkey私鑰的密碼,不填寫和keystore的密碼一致:123456
          就可以生成kserver.keystore文件
          server.keystore是給服務端用的,其中保存著自己的私鑰

          2)根據私鑰,導出服務端證書
          keytool -export -alias serverkey -keystore kserver.keystore -file server.crt
          server.crt就是服務端的證書

          3)將服務端證書,導入到客戶端的Trust KeyStore中
          keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
          tclient.keystore是給客戶端用的,其中保存著受信任的證書

          采用同樣的方法,生成客戶端的私鑰,客戶端的證書,并且導入到服務端的Trust KeyStore中
          1)keytool -genkey -alias clientkey -keystore kclient.keystore
          2)keytool -export -alias clientkey -keystore kclient.keystore -file client.crt
          3)keytool -import -alias clientkey -file client.crt -keystore tserver.keystore

          如此一來,生成的文件分成兩組
          服務端保存:kserver.keystore tserver.keystore
          客戶端保存:kclient.keystore  tclient.kyestore

          接下來,就采用JSSE,分別生成SSLServerSocket,SSLSocket

          服務端,生成SSLServerSocket代碼
          SSLContext ctx = SSLContext.getInstance("SSL");

          KeyManagerFactory kmf 
          = KeyManagerFactory.getInstance("SunX509");
          TrustManagerFactory tmf 
          = TrustManagerFactory.getInstance("SunX509");

          KeyStore ks 
          = KeyStore.getInstance("JKS");
          KeyStore tks 
          = KeyStore.getInstance("JKS");

          ks.load(
          new FileInputStream("data/kserver.keystore"), SERVER_KEY_STORE_PASSWORD.toCharArray());
          tks.load(
          new FileInputStream("data/tserver.keystore"), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());

          kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
          tmf.init(tks);

          ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), 
          null);

          return (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);

          客戶端,生成SSLSocket的代碼,大同小異
          SSLContext ctx = SSLContext.getInstance("SSL");

          KeyManagerFactory kmf 
          = KeyManagerFactory.getInstance("SunX509");
          TrustManagerFactory tmf 
          = TrustManagerFactory.getInstance("SunX509");

          KeyStore ks 
          = KeyStore.getInstance("JKS");
          KeyStore tks 
          = KeyStore.getInstance("JKS");

          ks.load(
          new FileInputStream("data/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
          tks.load(
          new FileInputStream("data/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());

          kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
          tmf.init(tks);

          ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), 
          null);

          return (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);

          如此,就完成了服務端和客戶端之間的基于身份認證的交互。

          client采用kclient.keystore中的clientkey私鑰進行數據加密,發(fā)送給server
          server采用tserver.keystore中的client.crt證書(包含了clientkey的公鑰)對數據解密,如果解密成功,證明消息來自client,進行邏輯處理

          server采用kserver.keystore中的serverkey私鑰進行數據叫米,發(fā)送給client
          client采用tclient.keystore中的server.crt證書(包含了serverkey的公鑰)對數據解密,如果解密成功,證明消息來自server,進行邏輯處理

          如果過程中,解密失敗,那么證明消息來源錯誤。不進行邏輯處理。這樣就完成了雙向的身份認證。

          下面我附上簡單的SSLServer.java SSLClient.java,供大家演示用。
          啟動服務端的時候,大家不妨采用telnet 127.0.0.1 7777連接,看看能不能實現(xiàn)消息傳遞。

          ssl demo
          備注:
          demo是采用maven構建項目的
          demo文件的編碼是用utf8,為了避免中文亂碼,請把workspace設置成utf8編碼

          posted on 2007-12-20 14:04 stone2083 閱讀(43501) 評論(8)  編輯  收藏 所屬分類: java

          Feedback

          # re: SSL雙向認證java實現(xiàn) 2008-01-05 22:37 jzp

          不錯,正需要.以后多些文章分享,辛苦了.  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-04-18 11:41 wangpeng

          我用你的方法試了,的確可以實現(xiàn)ssl加密傳輸,但是我重新生成客戶端證書后,并沒有加載到服務器端的信任庫tserver.keystore中,但是仍然可以通訊,這樣就是我隨便生成個客戶端證書只要有服務器的證書就可以通訊了,沒有真正意義上達到雙向認證,如何解決這個問題,請指教  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-04-18 11:43 wangpeng

          我的msn是steve_king211@msn.com,希望加上我,請教一些問題  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-04-20 17:18 stone2083

          謝謝wangpeng朋友,找到上原先demo中的一個問題。
          因為在Server端程序中,初始化的SSLServreSocket
          serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
          少寫了條語句:serverSocket.setNeedClientAuth(true); //表明需要驗證客戶端的身份。

          由于原demo程序,不需要客戶端身份驗證,所以即使服務端沒有客戶端證書,也能完成通訊。

          受限于自己對jsse理解非常的淺,上面的文章僅僅是覆蓋了jsse很表層的內容。
          推薦ibm網站上的一篇文章,對jsse和ssl寫得很深入淺出。
          為高級 JSSE 開發(fā)人員定制 :http://www.ibm.com/developerworks/cn/java/j-customssl/

          如有問題,歡迎再交流 :)
            回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-07-10 20:56 JessonWoo

          請問單向認證,即客戶端對服務器端的認證,需要為客戶端配置證書嗎,
          具體用java如何實現(xiàn)查看服務器端證書的功能,
          盼高手賜教!  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-07-14 13:21 stone2083

          @JessonWoo
          hi,首先申明下,我自己對ssl的認識還是很膚淺的,僅僅上次和cnnic合作的時候,為了了解安全性問題,才被迫稍微看了相應的一些知識.

          所謂認證,是要對某臺(當然可以是集群)服務器身份做認證.
          認證方式有兩種:
          自簽名認證:服務端生成key,然后根據key導出證書.公布于站點.
          通過第三方認證機構認證:有服務端生成key,然后導出認證信息,交由天威誠信等第三方認證機構認證,最后生成證書,公布于站點.

          客戶端,將證書下載,確認為可信任公司認證信息,并且導入到受信任區(qū)(trustscore),建立連接與服務端進行正常交互.至此,就完成了對服務端的認證.
          所以客戶端必須將證書導入信任區(qū).

          java中,可以查看證書:
          寫個簡單的方法:
          FileInputStream fis = new FileInputStream("cert.cer");
          CertificateFactory cf=CertificateFactory.getInstance("X509");
          X509Certificate c=(X509Certificate) cf.generateCertificate(fis);
          System.out.println(c.getSubjectDN());
          //可以查看下X509Certificate的一些get方法.

          其實keytool僅僅是jdk中的工具.
          openssl是更常用的一個工具
          可見:http://www.openssl.org/  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2008-11-17 14:00 le

          強身份認證演示:https://www.wosign.com/logindemo/  回復  更多評論   

          # re: SSL雙向認證java實現(xiàn) 2012-12-20 21:29 郭建軍

          雙向要加setNeedClientAuth(true)吧,你這是單向的  回復  更多評論   

          主站蜘蛛池模板: 大同市| 宁德市| 公安县| 汉源县| 米泉市| 商丘市| 新宾| 济南市| 保山市| 永年县| 信丰县| 田林县| 屏山县| 清水县| 南郑县| 宝坻区| 津南区| 高雄县| 华亭县| 改则县| 梅州市| 诸城市| 湾仔区| 乃东县| 中牟县| 肥东县| 武定县| 英德市| 张家口市| 色达县| 太仆寺旗| 玛曲县| 铁力市| 册亨县| 大连市| 漳平市| 长葛市| 苍溪县| 秦安县| 申扎县| 乐东|