天天看點

Java實作 SSL雙向認證

我們常見的SSL驗證較多的隻是驗證我們的伺服器是否是真實正确的,當然如果你通路的URL壓根就錯了,那誰也沒有辦法。這個就是所謂的SSL單向認證。

但是實際中,我們有可能還會驗證用戶端是否符合要求,也就是給我們每個使用者頒發一個證書,比且每個數字證書都是唯一的,不公開的。這樣就能通過這個數字證書保證目前通路我伺服器的這個使用者是經過伺服器認可的,其他人不可通路。

雙向認證 從第一個層面上 確定了伺服器 與用戶端 都是互相認可的。那麼他們之間要進行通信,就會在通信協定上附加SSL協定,確定通信的内容是加密的,即使是sniffer這樣的網絡嗅探工具看到的都是亂碼。以後給大家示範下不加密的情況下,用sniffer看到的是什麼。恐怕這樣你就能提高警惕了。

以下内容從網絡上摘抄 加以實際驗證後修改的。

模拟場景:

Server端和Client端通信,需要進行授權和身份的驗證,即Client隻能接受Server的消息,Server隻能接受Client的消息。

實作技術:

JSSE(Java Security Socket Extension)

是Sun為了解決在Internet上的安全通訊而推出的解決方案。它實作了SSL和TSL(傳輸層安全)協定。在JSSE中包含了資料加密,伺服器驗證,消息完整性和用戶端驗證等技術。通過使用JSSE,開發人員可以在客戶機和伺服器之間通過TCP/IP協定安全地傳輸資料。

為了實作消息認證。

Server需要:

1)KeyStore: 其中儲存服務端的私鑰

2)Trust KeyStore:其中儲存用戶端的授權證書

同樣,Client需要:

1)KeyStore:其中儲存用戶端的私鑰

2)Trust KeyStore:其中儲存服務端的授權證書

在這裡我還是推薦使用Java自帶的keytool指令,去生成這樣資訊檔案。當然目前非常流行的開源的生成SSL證書的還有OpenSSL。OpenSSL用C語言編寫,跨系統。但是我們可能在以後的過程中用java程式生成證書的友善性考慮,還是用JDK自帶的keytool。

1)生成服務端私鑰,并且導入到服務端KeyStore檔案中

keytool -genkey -alias serverkey -keystore kserver.keystore

過程中,分别需要填寫,根據需求自己設定就行

keystore密碼:123456

名字和姓氏:jin

組織機關名稱:none

組織名稱:none

城市或區域名稱:BJ

州或省份名稱:BJ

國家代碼:CN

serverkey私鑰的密碼,不填寫和keystore的密碼一緻。這裡千萬注意,直接回車就行了,不用修改密碼。否則在後面的程式中以及無法直接應用這個私鑰,會報錯。

就可以生成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

Java實作 SSL雙向認證

以下是通過Java Socket通信程式來驗證我們生成的證書是否可用。

用戶端:

用戶端代碼  

Java實作 SSL雙向認證
  1. package examples.ssl;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.BufferedOutputStream;  
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.security.KeyStore;  
  9. import javax.net.ssl.KeyManagerFactory;  
  10. import javax.net.ssl.SSLContext;  
  11. import javax.net.ssl.SSLSocket;  
  12. import javax.net.ssl.TrustManagerFactory;  
  13. public class SSLClient {  
  14.     private static final String DEFAULT_HOST                    = "127.0.0.1";  
  15.     private static final int    DEFAULT_PORT                    = 7777;  
  16.     private static final String CLIENT_KEY_STORE_PASSWORD       = "123456";  
  17.     private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";  
  18.     private SSLSocket           sslSocket;  
  19.     public static void main(String[] args) {  
  20.         SSLClient client = new SSLClient();  
  21.         client.init();  
  22.         client.process();  
  23.     }  
  24.     public void process() {  
  25.         if (sslSocket == null) {  
  26.             System.out.println("ERROR");  
  27.             return;  
  28.         }  
  29.         try {  
  30.             InputStream input = sslSocket.getInputStream();  
  31.             OutputStream output = sslSocket.getOutputStream();  
  32.             BufferedInputStream bis = new BufferedInputStream(input);  
  33.             BufferedOutputStream bos = new BufferedOutputStream(output);  
  34.             bos.write("Client Message".getBytes());  
  35.             bos.flush();  
  36.             byte[] buffer = new byte[20];  
  37.             bis.read(buffer);  
  38.             System.out.println(new String(buffer));  
  39.             sslSocket.close();  
  40.         } catch (IOException e) {  
  41.             System.out.println(e);  
  42.         }  
  43.     }  
  44.     public void init() {  
  45.         try {  
  46.             SSLContext ctx = SSLContext.getInstance("SSL");  
  47.             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");  
  48.             TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");  
  49.             KeyStore ks = KeyStore.getInstance("JKS");  
  50.             KeyStore tks = KeyStore.getInstance("JKS");  
  51.             ks.load(new FileInputStream("E://kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());  
  52.             tks.load(new FileInputStream("E://tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());  
  53.             kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());  
  54.             tmf.init(tks);  
  55.             ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);  
  56.             sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);  
  57.         } catch (Exception e) {  
  58.             System.out.println(e);  
  59.         }  
  60.     }  
  61. }  

伺服器端:

Java代碼  

Java實作 SSL雙向認證
  1. package examples.ssl;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.BufferedOutputStream;  
  4. import java.io.FileInputStream;  
  5. import java.io.InputStream;  
  6. import java.io.OutputStream;  
  7. import java.net.Socket;  
  8. import java.security.KeyStore;  
  9. import javax.net.ssl.KeyManagerFactory;  
  10. import javax.net.ssl.SSLContext;  
  11. import javax.net.ssl.SSLServerSocket;  
  12. import javax.net.ssl.TrustManagerFactory;  
  13. public class SSLServer {  
  14.     private static final int    DEFAULT_PORT                    = 7777;  
  15.     private static final String SERVER_KEY_STORE_PASSWORD       = "123456";  
  16.     private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "123456";  
  17.     private SSLServerSocket     serverSocket;  
  18.     public static void main(String[] args) {  
  19.         SSLServer server = new SSLServer();  
  20.         server.init();  
  21.         server.start();  
  22.     }  
  23.     public void start() {  
  24.         if (serverSocket == null) {  
  25.             System.out.println("ERROR");  
  26.             return;  
  27.         }  
  28.         while (true) {  
  29.             try {  
  30.                 Socket s = serverSocket.accept();  
  31.                 InputStream input = s.getInputStream();  
  32.                 OutputStream output = s.getOutputStream();  
  33.                 BufferedInputStream bis = new BufferedInputStream(input);  
  34.                 BufferedOutputStream bos = new BufferedOutputStream(output);  
  35.                 byte[] buffer = new byte[20];  
  36.                 bis.read(buffer);  
  37.                 System.out.println(new String(buffer));  
  38.                 bos.write("Server Echo".getBytes());  
  39.                 bos.flush();  
  40.                 s.close();  
  41.             } catch (Exception e) {  
  42.                 System.out.println(e);  
  43.             }  
  44.         }  
  45.     }  
  46.     public void init() {  
  47.         try {  
  48.             SSLContext ctx = SSLContext.getInstance("SSL");  
  49.             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");  
  50.             TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");  
  51.             KeyStore ks = KeyStore.getInstance("JKS");  
  52.             KeyStore tks = KeyStore.getInstance("JKS");  
  53.             ks.load(new FileInputStream("E://kserver.keystore"), SERVER_KEY_STORE_PASSWORD.toCharArray());  
  54.             tks.load(new FileInputStream("E://tserver.keystore"), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());  
  55.             kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());  
  56.             tmf.init(tks);  
  57.             ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);  
  58.             serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);  
  59.             serverSocket.setNeedClientAuth(true);   
  60.         } catch (Exception e) {  
  61.             e.printStackTrace();  
  62.         }  
  63.     }  
  64. }