JAVA基於HTTPS的加密遠程調用的實現

來源:互聯網
上載者:User

ServicePlatform-v2最終通過HTTPS強加密實現了通訊的安全傳輸,畢竟傳輸的都是關鍵的使用者帳號,而且我們現在還沒有自己的專用網路.
ServicePlatform 的RMI使用的輕量級Hessian或Burlup協議是基於HTTP協議的,如果部署得當,在沒有惡意竊聽的情況下是不會出現使用者資訊洩漏的問題, 但是一旦平台啟用後RMI調用被惡意截獲,那麼在request裡設計的註冊服務的密碼驗證和使用者資訊都將實效,SP平台的介面暴露,使用者資訊洩漏. 徹底的解決方案就是強制HTTPS方式訪問RMI介面,而HTTPS對於HTTP是協議本身是透明的(所謂嵌套層的由來),所以HTTPS可以在不修改 SP的代碼的(配置描述符的修改當然避免不了)情況下實現RMI通訊的強加密,而且也確實如此.
ServicePlatform的預設部署是強制 HTTPS訪問RMI介面,使用ServicePlatform的用戶端除了需要配置為HTTPS的invoker的地址外,還需要獲得 ServicePlatform的認證,否則JSSE將不會正常工作.下面是部署描述符web.xml裡面強制HTTPS訪問的部分.

<!-- comment below to enable plain HTTP invoker rather than HTTPS only --><security-constraint>    <web-resource-collection>        <web-resource-name>remote</web-resource-name>        <url-pattern>/remote/*</url-pattern>    </web-resource-collection>    <user-data-constraint>        <transport-guarantee>CONFIDENTIAL</transport-guarantee>    </user-data-constraint></security-constraint>

ServicePlatform的認證的產生由Java的keygen完成
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keypass changeit -keyalg RSA -validity 365
其中,changeit為密鑰的產生密碼,需要與tomcat的伺服器部署描述符一致,參考下面的server.xml的片斷

<Connector port="8443" maxHttpHeaderSize="8192"               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"               enableLookups="false" disableUploadTimeout="true"               acceptCount="100" scheme="https" secure="true"               clientAuth="false" sslProtocol="TLS" keystorePass="changeit" keystoreFile="conf/keystore"/>

產生認證時必須填寫正確的ServicePlatform啟動並執行伺服器的FQDN,然後和service-dist.properties檔案中的invoker的URL的FQDN完全一致,
否則JSSE將認證視為無效,無法建立HTTPS串連,然後在啟動用戶端的時候需要添加指向認證的JVM參數
-Djavax.net.ssl.trustStore=path\to\your\generated\keystore\file

應用伺服器和JDK版本資訊
Application Server tomcat-5.5.15
JDK 1.5.0_06

Java應用Tomcat中實現https安全連線的方法

SSL, 或者Secure Socket Layer,是一種允許web瀏覽器和web伺服器通過一個安全的串連進行交流的技術。這意味著將被發送的資料在一端被翻譯成密碼,傳送出去,然後在另一端解開密碼,再進行處理。這是一個雙向的過程,也就是瀏覽器和伺服器都需要在發送資料之前對它們進行加密。

SSL協定的另一個重要方面是認證(Authentication)。這就是說,在你開始試圖通過一個安全連線與一個web伺服器交流的時候,這個伺服器會要求你的瀏覽器出示一組證件,通過“評鑑”的方式來證明這就是你所聲明的網站。

在某些情況下,伺服器還會要求你的web瀏覽器的認認證,證明你就是你所說的那個人。這就是所知的“客戶認證”,儘管實際情況中,更多地用在商務-對-商務(B2B)交易,而不是對個人使用者。

但大多數有SSL功能的web伺服器不要求客戶認證(Client Authentication)。

認證

為了能實施SSL,一個web伺服器對每個接受安全連線的外部介面(IP 位址)必須要有相應的認證(Certificate)。關於這個設計的理論是一個伺服器必須提供某種合理的保證以證明這個伺服器的主人就是你所認為的那個人。這個認證要陳述與這個網站相關聯的公司,以及這個網站的所有者或系統管理員的一些基本聯絡資訊。

這個認證由所有人以密碼方式簽字,其他人非常難偽造。對於進行電子商務(e-commerce)的網站,或其他身份認證至關重要的任何商業交易,認認證要向大家所熟知的認證權威(Certificate Authority (CA))如VeriSign或Thawte來購買。這樣的認證可用電子技術證明屬實。實際上,認證權威單位會擔保它發出的認認證的真實性,如果你信任發出認認證的認證權威單位的話,你就可以相信這個認認證是行У摹?/font>

在許多情況下,認證並不是真正使人擔憂的事。系統管理員或許只想要保證被伺服器傳送和接收的資料是秘密的,不會被連接線上的偷竊者盜竊到。慶幸的是,Java提供相對簡單的被稱為keytool的命令列工具,可以簡單地產生“自己簽名”的認證。自己簽名的認證只是使用者產生的認證,沒有正式在大家所熟知的認證權威那裡註冊過,因此不能確保它的真實性。但卻能保證資料轉送的安全性。

認證也許很重要,也許不重要,完全決定於網站的需要。

用Tomcat來配置SSL主要有下面這麼兩大步驟:

一、產生認證

1、 在命令列下執行:

%Java_home%\bin\keytool -genkey -alias tomcat -keyalg RSA

在此命令中,keytool是JDK內建的產生認證的工具。把RSA運演算法則作為主要安全運演算法則,這保證了與其它伺服器和組件的相容性。

這個命令會在使用者的home directory產生一個叫做" .keystore " 的新檔案。在執行後,你首先被要求出示keystore密碼。Tomcat使用的預設密碼是" changeit "(全都是小寫字母),如果你願意,你可以指定你自己的密碼。你還需要在server.xml設定檔裡指定自己的密碼,這在以後會有描述。

2、 你會被要求出示關於這個認認證的一般性資訊,如公司,連絡人名稱,等等。這些資訊會顯示給那些試圖訪問你程式裡安全網頁的使用者,以確保這裡提供的資訊與他們期望的相對應。

3、 你會被要求出示密鑰(key)密碼,也就是這個認認證所特有的密碼(與其它的儲存在同一個keystore檔案裡的認認證不同)。你必須在這裡使用與keystore密碼相同的密碼。(目前,keytool會提示你按ENTER鍵會自動幫你做這些)。

如果一切順利,你現在就擁有了一個可以被你的伺服器使用的有認認證的keystore檔案。

二、配置tomcat

第二個大步驟是把secure socket配置在$CATALINA_HOME/conf/server.xml檔案裡。$CATALINA_HOME代表安裝Tomcat的目錄。一個例子是SSL連接器的元素被包括在和Tomcat一起安裝的預設server.xml檔案裡。它看起來象是這樣:

$CATALINA_HOME/conf/server.xml< -- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->< !--< Connectorport="8443" minProcessors="5" maxProcessors="75"enableLookups="true" disableUploadTimeout="true"acceptCount="100" debug="0" scheme="https" secure="true";clientAuth="false" sslProtocol="TLS"/>-->

Connector元素本身,其預設形式是被注釋掉的(commented out),所以需要把它周圍的注釋標誌刪除掉。然後,可以根據需要客戶化(自己設定)特定的屬性。一般需要增加一下keystoreFile和keystorePass兩個屬性,指定你存放認證的路徑(如:keystoreFile="C:/.keystore")和剛才設定的密碼(如:keystorePass="123456")。關於其它各種選項的詳細資料,可查閱Server Configuration Reference。

在完成這些配置更改後,必須象重新啟動Tomcat,然後你就可以通過SSL訪問Tomcat支援的任何web應用程式。只不過指令需要像下面這樣:https://localhost:8443

使用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是不一樣的,它需要一個認證來進行安全認證。

一、 認證

產生一個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

即:

public static void main(String args[]) {try {System.setProperty("javax.net.ssl.trustStore", (new PathTest()).getClass().getResource("/SSLKey").getFile()); 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);}}

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

執行用戶端可以有另一種方法,把認證拷貝到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.