用SSL構建安全的Socket

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是不同的,它須要一個證書來進行安全認證。
   
    1、 證書
   
    生成一個CA證書,在命令行下執行:
   
    keytool –genkey –keystore SSLKey –keyalg rsa –alias SSL
   
    黑體部分是用戶能夠本身指定的參數,第一個參數是要生成的證書的名字,第二個參數是證書的別名。rsa指明瞭咱們使用的加密方法。
   
    系統會要求輸入證書發放者的信息,逐項輸入便可,以下圖:
   
   
   
    系統生成的文件命將會和證書名相同。證書能夠提交給權威CA認證組織審覈,若是經過審覈,組織會提供信任擔保,向客戶擔保你的鏈接是安全的。固然這不是必須的。在咱們的例子中會把證書直接打包到客戶端程序中,保證客戶端是受權用戶,避免僞造客戶,因此不須要提交審覈。
   
    2、 服務器端
   
    如今能夠編寫服務器端的代碼,與普通的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端口等待鏈接…
   
    3、 客戶端
   
    客戶端的代碼相對簡單,咱們能夠不在程序中指定SSL環境,而是在執行客戶端程序時指定。須要注意的是客戶端並無導入證書,而是採用了默認的工廠方法構造SSLSocket:
   
    ● SSLSocketFactory factory=(SSLSocketFactory)SSLSocketFactory.getDefault();
   
    構造默認的工廠方法
   
    ●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,狀況可能會有不一樣。         若是程序客戶在不持有證書的狀況下直接進行鏈接,服務器端會產生運行時異常,不容許進行鏈接。
相關文章
相關標籤/搜索