使用SSL構建安全的Socket

來源:互聯網
上載者:User
使用SSL構建安全的Socket

 bromon原創 著作權

 SSL(安全套接層)是Netscape公司在1994年開發的,最初用於WEB瀏覽器,為瀏覽器與伺服器間的資料傳遞提供安全保障,提供了加密、來源認證和資料完整性的功能。現在SSL3.0得到了普遍的使用,它的改進版TLS(傳輸層安全)已經成為互連網標準。SSL本身和TCP通訊端串連是很相似的,在協議棧中,SSL可以被簡單的看作是安全的TCP串連,但是某些TCP串連的特性它是不支援的,比如帶外資料(out-of-bound)。

 在構建基於Socket的C/S程式時,通過添加對SSL的支援來保障資料安全和完整是不錯的方法。完善的Java為我們提供了簡單的實現方法:JSSE(Java安全通訊端擴充)。JSSE是一個純Java實現的SSL和TLS協議架構,抽象了SSL和TLS複雜的演算法,使安全問題變得簡單。JSSE已經成為J2SE1.4版本中的標準組件,支援SSL 3.0和TLS 1.0。我們將通過一個具體的例子示範JSSE的一些基本應用。例子中的伺服器端將開啟一個SSL Socket,只有持有指定認證的用戶端可以與它串連,所有的資料傳遞都是加密的。

 構造一個SSLSocket是非常簡單的:

 SSLServerSocketFactory factory=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
 SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(portNumber);
 SSLSocket socket = (SSLSocket);

 但是執行這樣的程式會產生一個異常,報告找不到可信任的認證。SSLSocket和普通的Socket是不一樣的,它需要一個認證來進行安全認證。

 一、 認證

 產生一個CA認證,在命令列下執行:

 keytool –genkey –keystore SSLKey –keyalg rsa –alias SSL

 黑體部分是使用者可以自己指定的參數,第一個參數是要產生的認證的名字,第二個參數是認證的別名。rsa指明了我們使用的加密方法。

 系統會要求輸入認證發放者的資訊,逐項輸入即可,如:

  

   系統產生的檔案命將會和認證名相同。認證可以提交給權威CA認證組織審核,如果通過審核,組織會提供信任擔保,向客戶擔保你的串連是安全的。當然這不是必須的。在我們的例子中會把認證直接打包到用戶端程式中,保證用戶端是授權使用者,避免偽造客戶,所以不需要提交審核。

 二、 伺服器端

 現在可以編寫伺服器端的代碼,與普通的Socket代碼不同,我們需要在程式中匯入認證,並使用該認證構造SSLSocket。需要的說明的是:

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

 訪問Java密鑰庫,JKS是keytool建立的Java密鑰庫,儲存密鑰。

 ● KeyManagerFactory kmf=KeyManagerFactory.getInstance("SunX509");

 建立用於管理JKS密鑰庫的X.509密鑰管理器。

 ● SSLContext sslContext=SSLContext.getInstance("SSLv3");

 構造SSL環境,指定SSL版本為3.0,也可以使用TLSv1,但是SSLv3更加常用。

 ●sslContext.init(kmf.getKeyManagers(),null,null);

 初始化SSL環境。第二個參數是告訴JSSE使用的可信任認證的來源,設定為null是從javax.net.ssl.trustStore中獲得認證。第三個參數是JSSE產生的隨機數,這個參數將影響系統的安全性,設定為null是個好選擇,可以保證JSSE的安全性。

 完整代碼如下:

 /*
 *SSL Socket的伺服器端
 *@Author Bromon
 */

 package org.ec107.ssl;

 import java.net.*;
 import javax.net.ssl.*;
 import java.io.*;
 import java.security.*;

 public class SSLServer
 {
  static int port=8266;  //系統將要監聽的連接埠號碼,82.6.6是偶以前女朋友的生日^_^
  static SSLServerSocket server;
  
  /*
  *建構函式
  */
  
  public SSLServer()
  {
   
  }
  
  
  /*
  *@param port 監聽的連接埠號碼
  *@return 返回一個SSLServerSocket對象
  */
  
  private static SSLServerSocket getServerSocket(int thePort)
  {
   SSLServerSocket s=null;
   try
   {
    String key="SSLKey";  //要使用的認證名

    char keyStorePass[]="12345678".toCharArray();  //認證密碼

    char keyPassword[]="12345678".toCharArray();  //認證別稱所使用的主要密碼

    KeyStore ks=KeyStore.getInstance("JKS");  //建立JKS密鑰庫

    ks.load(new FileInputStream(key),keyStorePass);

    //建立管理JKS密鑰庫的X.509密鑰管理器
    KeyManagerFactory kmf=KeyManagerFactory.getInstance("SunX509");

    kmf.init(ks,keyPassword);

    SSLContext sslContext=SSLContext.getInstance("SSLv3");

    sslContext.init(kmf.getKeyManagers(),null,null);
  
    //根據上面配置的SSL上下文來產生SSLServerSocketFactory,與通常的產生方法不同
    SSLServerSocketFactory factory=sslContext.getServerSocketFactory();

    s=(SSLServerSocket)factory.createServerSocket(thePort);

   }catch(Exception e)
   {
    System.out.println(e);
   }
   return(s);
  }
  
  
  public static void main(String args[])
  {
   try
   {
    server=getServerSocket(port);
    System.out.println("在”+port+”連接埠等待串連...");

    while(true)
    {
     SSLSocket socket=(SSLSocket)server.accept();
     
     //將得到的socket交給CreateThread對象處理,主線程繼續監聽
     new CreateThread(socket);
     
    }
   }catch(Exception e)
   {
    System.out.println("main方法錯誤80:"+e);
   }
  }
 }

 /*
 *內部類,獲得主線程的socket串連,產生子線程來處理
 */

 class CreateThread extends Thread
 {
  static BufferedReader in;
  static PrintWriter out;
  static Socket s;
  
  /*
  *建構函式,獲得socket串連,初始化in和out對象
  */
  
  public CreateThread(Socket socket)
  {
   try
   {
    s=socket;
    in=new BufferedReader(new InputStreamReader(s.getInputStream(),"gb2312"));

    out=new PrintWriter(s.getOutputStream(),true);

    start();  //開新線程執行run方法

   }catch(Exception e)
   {
    System.out.println(e);
   }
   
  }
  
  /*
  *線程方法,處理socket傳遞過來的資料
  */
  
  public void run()
  {
   try
   {
    String msg=in.readLine();
    System.out.println(msg);
    s.close();
   }catch(Exception e)
   {
    System.out.println(e);
   }
  }
 }

 將我們剛才產生的認證放到程式所在的目錄下,上面的代碼就可以在編譯之後執行:

 java org.ec107.ssl.SSLServer

 在8266連接埠等待串連…

 三、 用戶端

 用戶端的代碼相對簡單,我們可以不在程式中指定SSL環境,而是在執行用戶端程式時指定。需要注意的是用戶端並沒有匯入認證,而是採用了預設的Factory 方法構造SSLSocket:

 ● SSLSocketFactory factory=(SSLSocketFactory)SSLSocketFactory.getDefault();

 構造預設的Factory 方法

 ●Socket s=factory.createSocket("localhost",port);

 開啟一個SSLSocket串連

 /*
 *SSL Socket 的用戶端
 *@Author Bromon
 */

 package org.ec107.ssl;

 import java.net.*;
 import javax.net.ssl.*;
 import javax.net.*;
 import java.io.*;

 public class SSLClient
 {
  static int port=8266;
  public static void main(String args[])
  {
   try
   {
    SSLSocketFactory factory=(SSLSocketFactory)SSLSocketFactory.getDefault();

    Socket s=factory.createSocket("localhost",port);
    
    PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    out.println("安全的說你好");
    out.close();
    s.close();
   }catch(Exception e)
   {
    System.out.println(e);
   }
  }
 }

 把伺服器產生的認證(SSLKey)拷貝到程式所在的目錄,執行這個程式的時候需要向javax.net.ssl.trustStore環境變數傳入認證名:

 java –Djavax.net.ssl.trustStore=SSLKey org.ec107.ssl.SSLClient

 可以在伺服器的控制台看到用戶端發送過來的資料。

 執行用戶端可以有另一種方法,把認證拷貝到java home/lib/security目錄下,名字改為jssecacerts,然後可以直接執行用戶端:

 java org.ec107.ssl.SSLClient

 程式會自動的到上述目錄下去尋找jssecacerts檔案作為預設的認證。需要注意的是這裡的java home並不是我們在安裝J2SE時指定的那個JAVA_HOME。可以執行一個程式來得到java home的位置:

 public class GetJavaHome
 {
   public static void main(String args[])
   {
     System.out.println(System.getProperty(“java.home”));
   }
 }

 一般情況下(windows 2K)hava home的位置是在C:Program FilesJavaj2re1.4.0_02,相對的,認證就應該拷貝到C:Program FilesJavaj2re1.4.0_02libsecurity下,如果安裝了內建JDK的Java IDE,比如JBuilder,情況可能會有不同。

   如果程式客戶在不持有認證的情況下直接進行串連,伺服器端會產生運行時異常,不允許進行串連。

 運行環境:windows 2K server,j2sdk1.4.1

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.