首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實作 SSL 雙向認證完整教學:從金鑰生成到 Socket 通訊驗證

     編輯:Java 相關知識

前言:單向與雙向認證的差異

常見的 SSL 單向認證僅驗證伺服器身分,確保用戶連線至真實網站。然而企業級應用常需雙向認證:伺服器與客戶端互相驗證身分,雙方各持有唯一、非公開的數位憑證,確保通訊雙方均受信任,並透過 SSL 協定加密傳輸內容,防止網路嗅探工具竊取資料。

核心架構與檔案準備

採用 JSSE(Java Security Socket Extension)實作 SSL/TLS 協定。雙方皆需兩組 Keystore:

  • 伺服器端:KeyStore(儲存私鑰)+ Trust KeyStore(儲存客戶端信任憑證)
  • 客戶端:KeyStore(儲存私鑰)+ Trust KeyStore(儲存伺服器信任憑證)

建議使用 JDK 內建 keytool 指令生成,便於後續 Java 程式整合。OpenSSL 雖跨平台但以 C 撰寫,整合較繁瑣。

步驟一:生成伺服器端金鑰與憑證

# 1. 產生私鑰並存入 kserver.keystore
keytool -genkey -alias serverkey -keystore kserver.keystore
# 密碼設為 123456,私鑰密碼直接按 Enter 沿用 keystore 密碼(關鍵細節)

# 2. 匯出伺服器憑證
keytool -export -alias serverkey -keystore kserver.keystore -file server.crt

# 3. 將伺服器憑證匯入客戶端 Trust Store
keytool -import -alias serverkey -file server.crt -keystore tclient.keystore

步驟二:生成客戶端金鑰與憑證(同理)

keytool -genkey -alias clientkey -keystore kclient.keystore
keytool -export -alias clientkey -keystore kclient.keystore -file client.crt
keytool -import -alias clientkey -file client.crt -keystore tserver.keystore

最終檔案分佈:

  • 伺服器端:kserver.keystore、tserver.keystore
  • 客戶端:kclient.keystore、tclient.keystore

程式碼實作驗證

客戶端 SSLClient.java

public class SSLClient {
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 7777;
    private static final String PWD = "123456";

    public static void main(String[] args) {
        new SSLClient().init().process();
    }

    public SSLClient init() {
        try {
            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("E:/kclient.keystore"), PWD.toCharArray());
            tks.load(new FileInputStream("E:/tclient.keystore"), PWD.toCharArray());

            kmf.init(ks, PWD.toCharArray());
            tmf.init(tks);
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket(HOST, PORT);
        } catch (Exception e) { e.printStackTrace(); }
        return this;
    }

    public void process() {
        // 發送 "Client Message" 並接收回應...
    }
}

伺服器端 SSLServer.java

public class SSLServer {
    private static final int PORT = 7777;
    private static final String PWD = "123456";

    public static void main(String[] args) {
        new SSLServer().init().start();
    }

    public SSLServer init() {
        try {
            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("E:/kserver.keystore"), PWD.toCharArray());
            tks.load(new FileInputStream("E:/tserver.keystore"), PWD.toCharArray());

            kmf.init(ks, PWD.toCharArray());
            tmf.init(tks);
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(PORT);
            serverSocket.setNeedClientAuth(true); // 強制雙向認證
        } catch (Exception e) { e.printStackTrace(); }
        return this;
    }

    public void start() {
        // 單執行緒迴圈 accept、讀取、回覆 "Server Echo"...
    }
}

關鍵提醒

  1. 私鑰密碼務必與 Keystore 密碼一致(按 Enter 跳過),否則程式載入私鑰會報錯。
  2. serverSocket.setNeedClientAuth(true) 是啟用雙向認證的關鍵。
  3. 實際部署時請使用絕對路徑或資源流讀取 Keystore,避免硬編碼路徑。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved