溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

創(chuàng)建基于SSL的安全服務(wù)器和安全客戶的范例

發(fā)布時間:2020-07-13 11:18:19 來源:網(wǎng)絡(luò) 閱讀:164 作者:孫衛(wèi)琴 欄目:編程語言

創(chuàng)建基于SSL的安全服務(wù)器和安全客戶的范例

以下內(nèi)容參考孫衛(wèi)琴所寫的《Java網(wǎng)絡(luò)編程核心技術(shù)詳解》一書的第15章。
源代碼下載地址為:http://lesson.javathinker.net/javanet/javanetsourcecode.rar

以下EchoServer類創(chuàng)建了一個基于SSL的安全服務(wù)器,它處于服務(wù)器模式。

/* EchoServer.java */
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;
public class EchoServer {
  private int port=8000;
  private SSLServerSocket serverSocket;

  public EchoServer() throws Exception {
    //輸出跟蹤日志
    //System.setProperty("javax.net.debug", "all");
    SSLContext context=createSSLContext();
    SSLServerSocketFactory factory=context.getServerSocketFactory();
    serverSocket =(SSLServerSocket)factory.createServerSocket(port);
    System.out.println("服務(wù)器啟動");
    System.out.println(
               serverSocket.getUseClientMode()? "客戶模式":"服務(wù)器模式");
    System.out.println(serverSocket.getNeedClientAuth()?
             "需要驗證對方身份":"不需要驗證對方身份");

    String[] supported=serverSocket.getSupportedCipherSuites();
    serverSocket.setEnabledCipherSuites(supported);
  }

  public SSLContext createSSLContext() throws Exception {
    //服務(wù)器用于證實自己身份的安全證書所在的密鑰庫
    String keyStoreFile = "test.keystore";
    String passphrase = "123456";
    KeyStore ks = KeyStore.getInstance("JKS");
    char[] password = passphrase.toCharArray();
    ks.load(new FileInputStream(keyStoreFile), password);
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, password);

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(kmf.getKeyManagers(), null, null);

    //當(dāng)要求客戶端提供安全證書時,服務(wù)器端可創(chuàng)建TrustManagerFactory,
    //并由它創(chuàng)建TrustManager,TrustManger根據(jù)與之關(guān)聯(lián)的KeyStore中的信息,
    //來決定是否相信客戶提供的安全證書。

    //客戶端用于證實自己身份的安全證書所在的密鑰庫
    //String trustStoreFile = "test.keystore";  
    //KeyStore ts = KeyStore.getInstance("JKS");
    //ts.load(new FileInputStream(trustStoreFile), password);
    //TrustManagerFactory tmf =
    //    TrustManagerFactory.getInstance("SunX509");
    //tmf.init(ts);
    //sslContext.init(kmf.getKeyManagers(),
    //                 tmf.getTrustManagers(), null);

    return sslContext;
  }

  public String echo(String msg) {
    return "echo:" + msg;
  }

  private PrintWriter getWriter(Socket socket)throws IOException{
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut,true);
  }
  private BufferedReader getReader(Socket socket)throws IOException{
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
  }

  public void service() {
    while (true) {
      Socket socket=null;
      try {
        socket = serverSocket.accept();  //等待客戶連接
        System.out.println("New connection accepted "
                        +socket.getInetAddress()
                       + ":" +socket.getPort());
        BufferedReader br =getReader(socket);
        PrintWriter pw = getWriter(socket);

        String msg = null;
        while ((msg = br.readLine()) != null) {
          System.out.println(msg);
          pw.println(echo(msg));
          if (msg.equals("bye")) //如果客戶發(fā)送的消息為“bye”,就結(jié)束通信
            break;
        }
      }catch (IOException e) {
         e.printStackTrace();
      }finally {
         try{
           if(socket!=null)socket.close();  //斷開連接
         }catch (IOException e) {e.printStackTrace();}
      }
    }
  }

  public static void main(String args[])throws Exception {
    new EchoServer().service();
  }
}

以上EchoServer類先創(chuàng)建了SSLContext對象,然后由它創(chuàng)建SSLServerSocketFactory對象,再由該工廠對象創(chuàng)建SSLServerSocket對象。對于以下程序代碼:

System.out.println(serverSocket.getUseClientMode()?
               "客戶模式":"服務(wù)器模式");
System.out.println(serverSocket.getNeedClientAuth()?
               "需要驗證對方身份":"不需要需要驗證對方身份");

打印結(jié)果為:

服務(wù)器模式
不需要驗證對方身份

由此可見,默認(rèn)情況下,SSLServerSocket處于服務(wù)器模式,必須向?qū)Ψ阶C實自身的身份,但不需要驗證對方的身份,即不要求對方出示安全證書。

如果希望程序運行時輸出底層JSSE實現(xiàn)的日志信息,可以把“javax.net.debug”系統(tǒng)屬性設(shè)為“all”:
System.setProperty("javax.net.debug", "all");

以下EchoClient類創(chuàng)建了一個基于SSL的安全客戶,它處于客戶模式。

/* EchoClient.java */
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;
public class EchoClient {
  private String host="localhost";
  private int port=8000;
  private SSLSocket socket;

  public EchoClient()throws IOException{
    SSLContext context=createSSLContext();
    SSLSocketFactory factory=context.getSocketFactory();
    socket=(SSLSocket)factory.createSocket(host,port);
    String[] supported=socket.getSupportedCipherSuites();
    socket.setEnabledCipherSuites(supported);
    System.out.println(socket.getUseClientMode()?
                           "客戶模式":"服務(wù)器模式");
  }

  public SSLContext createSSLContext() throws Exception {
    String passphrase = "123456";
    char[] password = passphrase.toCharArray();

    //設(shè)置客戶端所信任的安全證書所在的密鑰庫
    String trustStoreFile = "test.keystore";    
    KeyStore ts = KeyStore.getInstance("JKS");
    ts.load(new FileInputStream(trustStoreFile), password);
    TrustManagerFactory tmf =
                 TrustManagerFactory.getInstance("SunX509");
    tmf.init(ts);

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null,tmf.getTrustManagers(), null);
    return sslContext;
  }
  public static void main(String args[])throws IOException{
    new EchoClient().talk();
  }
  private PrintWriter getWriter(Socket socket)throws IOException{
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut,true);
  }
  private BufferedReader getReader(Socket socket)throws IOException{
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
  }
  public void talk()throws IOException {
    try{
      BufferedReader br=getReader(socket);
      PrintWriter pw=getWriter(socket);
      BufferedReader localReader=
          new BufferedReader(new InputStreamReader(System.in));
      String msg=null;
      while((msg=localReader.readLine())!=null){
        pw.println(msg);
        System.out.println(br.readLine());

        if(msg.equals("bye"))
          break;
      }
    }catch(IOException e){
       e.printStackTrace();
    }finally{
       try{socket.close();}catch(IOException e){e.printStackTrace();}
    }
  }
}

以上EchoClient類先創(chuàng)建了一個SSLSocketFactory對象,然后由它創(chuàng)建了SSLSocket對象。對于以下程序代碼:

System.out.println(socket.getUseClientMode()?
                    "客戶模式":"服務(wù)器模式");

打印結(jié)果為:

客戶模式

由此可見,默認(rèn)情況下,由SSLSocketFactory創(chuàng)建的SSLSocket對象處于客戶模式,不必向?qū)Ψ阶C實自身的身份。
EchoClient類依靠TrustManager來決定是否信任EchoServer出示的安全證書。EchoClient類的SSLSocketFactory對象是由SSLContext對象來創(chuàng)建的。這個SSLContext對象通過TrustManager來管理所信任的安全證書。在本例中,TrustManager所信任的安全證書位于test.keystore密鑰庫文件中。

在本例中,服務(wù)器端向客戶端出示的安全證書位于test.keystore密鑰庫文件中。在實際應(yīng)用中,服務(wù)器端的密鑰庫文件中包含密鑰對,從安全角度出發(fā),客戶端所信任的密鑰庫文件中應(yīng)該僅僅包含公鑰,所以服務(wù)器和客戶端應(yīng)該使用不同的密鑰庫文件。

假定該文件與EchoServer.class以及EchoClient.class文件位于同一目錄下。在DOS命令行中轉(zhuǎn)到范例所在的chapter15目錄下,按照以下步驟運行EchoServer和EchoClient:
(1)設(shè)置classpath,運行命令“set classpath=C:\chapter15\classes”。
(2)運行“start java EchoServer”命令,啟動EchoServer服務(wù)器。
(3)運行“ java EchoClient”命令,啟動EchoClient客戶。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI