在網絡上信息由源主機到目標主機要經過很多路由和計算機,通常這些機器不會監聽路過的信息。但在使用網絡銀行進行網上消費時,不加以保護的賬號密碼很有可能被黑客截獲並利用給消費者造成不可估量的損失。
Java安全套接字擴展(JSSE,Java Secure Socket Extension)爲基於SSL和TLS協議的Java網絡應用程序提供了Java API及參考實現。JSSE支持數據加密、服務器端身份驗證、數據完整性。使用JSSE,能保證採用各種應用層協議(HTTP、Telnet、FTP等)的客戶程序與服務器程序安全地交換數據
要實現用JSSE交換數據,需要用到證書,獲取證書有兩種方式,一是從權威機構購買證書,二是創建自我簽名的證書。我們用JDK現有的工具keytool創建一個自我簽名的證書。
服務端證書
客戶端證書
jks文件是一個密鑰容器,證書都會存儲在裏面,如果要導出剛剛生成的證書,用下面的命令
keytool -export -alias keyAlias
-storepass changeit
-file server.cer
-keystore keystore.jks
JSSE中負責安全通信的核心類是SSLServerSocket類和SSLSocket類,它們分別是ServerSocket與Socket類的子類。SSLSocket對象由SSLSocketFactory創建,不過SSLServerSocket的accept()方法也會創建SSLSocket。SSLServerSocketFactory、SSLSocketFactory對象都由SSLContext對象創建。
下面是一個簡單的例子,客戶端和服務端採用剛纔生成的兩個證書進行通信,在控制檯隨便輸入信息,服務端都會響應,輸入"88"結束本次會話。
客戶端:
- package com.bill99.seashell.domain;
- import java.io.BufferedReader;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.security.KeyStore;
- import javax.net.ssl.KeyManagerFactory;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLSocket;
- import javax.net.ssl.SSLSocketFactory;
- import javax.net.ssl.TrustManagerFactory;
- public class MySSLClient {
- private static final String SSL_TYPE = "SSL";
- private static final String X509 = "SunX509";
- private static final String KS_TYPE = "JKS";
- private SSLSocket sslcntSocket;
- public MySSLClient(String targetHost,int port) throws Exception {
- SSLContext sslContext = createSSLContext(); //創建SSL上下文
- SSLSocketFactory sslcntFactory =(SSLSocketFactory) sslContext.getSocketFactory();
- sslcntSocket = (SSLSocket) sslcntFactory.createSocket(targetHost, port);
- String[] supported = sslcntSocket.getSupportedCipherSuites();
- sslcntSocket.setEnabledCipherSuites(supported); //設置加密套件
- }
- private SSLContext createSSLContext() throws Exception{
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(X509);
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(X509);
- //-----------------------------------------------------------
- String clientKeyStoreFile = "c:\\merchant.jks"; //客戶端用於證實自己身份的證書
- String cntPassphrase = "baitour"; //證書密碼
- char[] cntPassword = cntPassphrase.toCharArray();
- KeyStore clientKeyStore = KeyStore.getInstance(KS_TYPE);
- clientKeyStore.load(new FileInputStream(clientKeyStoreFile),cntPassword);
- //-----------------------------------------------------------
- String serverKeyStoreFile = "c:\\paygateway.jks"; //服務端證書
- String svrPassphrase = "99bill"; //證書密碼
- char[] svrPassword = svrPassphrase.toCharArray();
- KeyStore serverKeyStore = KeyStore.getInstance(KS_TYPE);
- serverKeyStore.load(new FileInputStream(serverKeyStoreFile), svrPassword);
- kmf.init(clientKeyStore, cntPassword);
- tmf.init(serverKeyStore); //添加信任的證書
- SSLContext sslContext = SSLContext.getInstance(SSL_TYPE);
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
- return sslContext;
- }
- /**
- * 發送消息至服務器
- * @param sayMsg 發送給服務器信息
- * @return String 服務器響應的信息
- * @throws IOException 發送過程Socket出錯時拋出此異常
- */
- public String sayToSvr(String sayMsg) throws IOException{
- BufferedReader ioReader = new BufferedReader(new InputStreamReader(
- sslcntSocket.getInputStream()));
- PrintWriter ioWriter = new PrintWriter(sslcntSocket.getOutputStream());
- ioWriter.println(sayMsg);
- ioWriter.flush();
- return ioReader.readLine();
- }
- public static void main(String[] args) throws Exception {
- MySSLClient mysslCnt = new MySSLClient("127.0.0.1",7612);
- BufferedReader ioReader = new BufferedReader(new InputStreamReader(System.in));
- String sayMsg = "";
- String svrRespMsg= "";
- while( (sayMsg = ioReader.readLine())!= null ) {
- svrRespMsg = mysslCnt.sayToSvr(sayMsg);
- if(svrRespMsg != null && !svrRespMsg.trim().equals("")) {
- System.err.println("服務器響應:"+svrRespMsg);
- }
- if(sayMsg.trim().equals("88")) {
- break ;
- }
- }
- }
- }
服務端
- package com.bill99.seashell.domain;
- import java.io.BufferedReader;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.security.KeyStore;
- import javax.net.ssl.KeyManagerFactory;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLServerSocket;
- import javax.net.ssl.SSLServerSocketFactory;
- import javax.net.ssl.SSLSocket;
- import javax.net.ssl.TrustManagerFactory;
- public class MySSLServer {
- private static final String SSL_TYPE = "SSL";
- private static final String KS_TYPE = "JKS";
- private static final String X509 = "SunX509";
- private final static int PORT = 7612; //監聽端口
- private final static Object lock = new Object();//對象鎖
- private static MySSLServer mysslServer;
- private SSLServerSocket svrSocket;
- /**
- * 通過單態模式獲得MySSLServer對象
- */
- public static MySSLServer getInstance() throws Exception {
- synchronized (lock) {
- if (mysslServer == null) {
- mysslServer = new MySSLServer();
- }
- return mysslServer;
- }
- }
- private MySSLServer() throws Exception{
- //輸出跟蹤日誌
- System.setProperty("javax.net.debug","all");
- //創建SSL上下文
- SSLContext sslContext = createSSLContext();
- SSLServerSocketFactory serverFactory = sslContext.getServerSocketFactory();
- svrSocket =(SSLServerSocket) serverFactory.createServerSocket(PORT);
- svrSocket.setNeedClientAuth(true); //需要驗證客戶的身份
- System.err.println("【SSL服務器啓動,監聽端口:"+PORT+ "】");
- System.err.println(svrSocket.getNeedClientAuth() ? "【需要驗證對方身份】" : "【不需要驗證對方的身份】");
- //設置支持加密的套件
- String[] supported = svrSocket.getEnabledCipherSuites();
- svrSocket.setEnabledCipherSuites(supported);
- }
- /**
- * 創建上下文
- * @return SSLContext
- * @throws Exception 在創建SSLContext發生錯誤時拋出此異常
- */
- private SSLContext createSSLContext() throws Exception{
- //證書管理器
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(X509);
- //信任管理器
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(X509);
- //服務器證書加載到證書管理器
- //----------------------------------------------------------
- String serverKeyStoreFile = "c:\\paygateway.jks"; //服務器用於證實自己身份的證書
- String svrPassphrase = "99bill"; //服務器證書密碼
- char[] svrPassword = svrPassphrase.toCharArray();
- KeyStore serverKeyStore = KeyStore.getInstance(KS_TYPE);
- serverKeyStore.load(new FileInputStream(serverKeyStoreFile), svrPassword);
- kmf.init(serverKeyStore, svrPassword);
- //客戶機證書加載到證書管理器
- //-----------------------------------------------------------
- String clientKeyStoreFile = "c:\\merchant.jks"; //客戶端用於證實自己身份的證書
- String cntPassphrase = "baitour"; //證書密碼
- char[] cntPassword = cntPassphrase.toCharArray();
- KeyStore clientKeyStore = KeyStore.getInstance(KS_TYPE);
- clientKeyStore.load(new FileInputStream(clientKeyStoreFile),cntPassword);
- tmf.init(clientKeyStore); //添加信任的證書
- SSLContext sslContext = SSLContext.getInstance(SSL_TYPE);
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
- return sslContext;
- }
- /**
- * 開始服務
- */
- public void startService() {
- SSLSocket cntSocket = null;
- BufferedReader ioReader = null;
- PrintWriter ioWriter = null;
- String tmpMsg = null;
- while( true ) {
- try {
- cntSocket =(SSLSocket) svrSocket.accept();
- System.err.println("[有客戶機連接,IP:"+cntSocket.getInetAddress()+"]");
- ioReader = new BufferedReader(new InputStreamReader(cntSocket.getInputStream()));
- ioWriter = new PrintWriter(cntSocket.getOutputStream());
- while ( (tmpMsg = ioReader.readLine()) != null) {
- System.err.println("[客戶機說:"+tmpMsg+"]");
- if("88".equals(tmpMsg)) {
- break;
- }
- tmpMsg = " **** Welcome to our website **** ";
- ioWriter.println(tmpMsg);
- ioWriter.flush();
- System.err.println("[服務器說:"+tmpMsg+"]");
- }
- } catch(IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if(cntSocket != null) cntSocket.close();
- } catch(Exception ex) {ex.printStackTrace();}
- }
- }//end while
- }//end startService method
- public static void main(String[] args) throws Exception {
- MySSLServer mysslSvr = MySSLServer.getInstance();
- mysslSvr.startService();
- }
- }