1. 程式人生 > >Tomcat SSL配置及Tomcat CA證書安裝

Tomcat SSL配置及Tomcat CA證書安裝

最近要做一個SSL的應用,用SSL進行雙向身份驗證意思就是在客戶機連線伺服器時,連結雙方都要對彼此的數字證書進行驗證,保證這是經過授權的才能夠連線。我們連結一般的SSL時採用的是單向驗證,客戶機只驗證伺服器的證書,伺服器不驗證客戶機的證書;而連線網上銀行時使用的U盾就是用來儲存進行雙向驗證所需要的客戶端證書的。

Tomcat既可以作為獨立的Servlet容器,也可以作為其他HTTP伺服器附加的Servlet容器。如果Tomcat在非獨立模式下工作,通常不必配置SSL,由它從屬的HTTP伺服器來實現和客戶的SSL通訊。Tomcat和HTTP伺服器之間的通訊無須採用加密機制,HTTP伺服器將解密後的資料傳給Tomcat,並把Tomcat發來的資料加密後傳給客戶。

如果Tomcat作為獨立的Java Web伺服器,則可以根據安全需要,為Tomcat配置SSL,它包含以下兩個步驟:

(1) 準備安全證書。

(2) 配置Tomcat的SSL聯結器(Connector)。

一、準備安全證書

獲得安全證書有兩種方式:一種方式是到權威機構購買,還有一種方式是建立自我簽名的證書。這裡就介紹第二種獲取證書的方式,畢竟免費的嘛!

SUN公司提供了製作證書的工具keytool。在JDK 1.4以後的版本中都包含了這一工具,它的位置為<JAVA_HOME>\bin\keytool.exe。

通過keytool工具建立證書的命令為:

keytool -genkeypair -alias "tomcat" -keyalg "RSA" 

以上命令將生產一對非對稱金鑰和自我簽名的證書,這個命令中幾個引數的意思如下:

-genkeypair:生成一對非對稱金鑰。-alias:指定金鑰對的別名,該別名是公開的。-keyalg:指定加密演算法,本例中的採用通用的RAS加密演算法

首先會提示輸入keystore的密碼。

然後提示輸入個人資訊,如姓名、組織單位和所在城市等,直接回車即可。

接著會提示輸入資訊是否正確,輸入“y”表示資訊正確。

最後要求輸入<Tomcat>的主密碼,這裡設定與keystore相同的密碼,因此只需根據提示按回車鍵即可。

二、配置SSL聯結器

在Tomcat的server.xml檔案中,已經提供了現成的配置SSL聯結器的程式碼,只要把<Connector>元素的註釋去掉即可:

<!—  Define a SSL HTTP/1.1 Connector on port 8443  This connector uses the JSSE configuration, when using APR, the   connector should be using the OpenSSL style configuration  described in the APR documentation   -->  

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"           maxThreads="150" scheme="https" secure="true"           clientAuth="false" sslProtocol="TLS"             keystoreFile="C:\Documents and Settings\XuLiang\.keystore"           keystorePass="SUNCHIS"           ciphers="sunchis" /> 

實際上,基於SSL的HTTPS使用的預設埠是443。但Tomcat在這裡將HTTPS埠設定為8443。<Connector>配置裡的一些屬性引數如下表:

clientAuth如果設為true(即雙向認證)

keystoreFile指定keystore檔案的存放位置

keystorePass指定keystore的密碼

三、訪問支援SSL的Web站點

由於SSL技術已建立到絕大多數瀏覽器和Web伺服器程式中,因此,僅需在Web伺服器端安裝伺服器證書就可以啟用SSL功能了。

如果上述的第一步和第二步已經配置完畢,那麼就可以重啟Tomcat伺服器了,然後從IE瀏覽器中以HTTPS方式來訪問在Tomcat伺服器上的任何一個Web應用。現在我們就來訪問一下這個地址:

四 、返回一個新的接受任意SSL證書的HttpClient(tomcat中clientAuth="false")

private DefaultHttpClient getIgnoreSSLHttpClient(int sslPort) throws Exception {

httpclient = new DefaultHttpClient();

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

X509TrustManager tm = new X509TrustManager() {

            public X509Certificate[] getAcceptedIssuers(){

                    return null;

            }

            public void checkClientTrusted(X509Certificate[] certs,

                            String authType) {

            }

            public void checkServerTrusted(X509Certificate[] certs,

                            String authType) {

            System.out.println("server:"+certs[0]);

            }

};

sslContext.init(null, new TrustManager[] {tm}, null);

SSLSocketFactory sf = new SSLSocketFactory(sslContext);

Scheme sch = new Scheme("https", sslPort, sf);

        httpclient.getConnectionManager().getSchemeRegistry().register(sch);

return httpclient;

}

五 、單向驗證SSL證書的HttpClient(tomcat中clientAuth="false")

private DefaultHttpClient getOneWayAuthSSLHttpClient(final String ip, int sslPort) throws Exception {

httpclient = new DefaultHttpClient();

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

X509TrustManager tm = new X509TrustManager() {

            public X509Certificate[] getAcceptedIssuers(){

                    return new X509Certificate[0];

            }

            public void checkClientTrusted(X509Certificate[] certs,

                            String authType) {

            }

            public void checkServerTrusted(X509Certificate[] certs,

                            String authType) throws CertificateException {

if (certs == null || certs.length == 0)

throw new IllegalArgumentException("null or zero-length certificate chain");

if (authType == null || authType.length() == 0)

throw new IllegalArgumentException("null or zero-length authentication type");

boolean br = false;

for (X509Certificate x509Certificate : certs) {

String issuer = x509Certificate.getIssuerDN().toString();

if(issuer.contains("CN=" + ip)){

br = true;

return;

}

}

if (!br) {

throw new CertificateException("authen failed!");

}

            }

};

sslContext.init(null, new TrustManager[] {tm}, null);

SSLSocketFactory sf = new SSLSocketFactory(sslContext);

Scheme sch = new Scheme("https", sslPort, sf);

        httpclient.getConnectionManager().getSchemeRegistry().register(sch);

return httpclient;

}

六 、雙向驗證SSL證書的HttpClient(tomcat中clientAuth="true")

Server需要:

1)KeyStore: 其中儲存服務端的私鑰

2)Trust KeyStore:其中儲存客戶端的授權證書

同樣,Client需要:

1)KeyStore:其中儲存客戶端的私鑰

2)Trust KeyStore:其中儲存服務端的授權證書

生成key和證書

1)生成服務端私鑰,並且匯入到服務端KeyStore檔案中

keytool -genkey -alias serverkey -keystore serverKey.keystore

2)根據私鑰,匯出服務端證書

keytool -export -alias serverkey -keystore serverKey.keystore -file server.crt

server.crt就是服務端的證書

3)將服務端證書,匯入到客戶端的Trust KeyStore中

keytool -import -alias serverkey -file server.crt -keystore serverCrt.keystore

tclient.keystore是給客戶端用的,其中儲存著受信任的證書

採用同樣的方法,生成客戶端的私鑰,客戶端的證書,並且匯入到服務端的Trust KeyStore中

1)keytool -genkey -alias clientkey -keystore clientKey.keystore

2)keytool -export -alias clientkey -keystore clientKey.keystore -file client.crt

3)keytool -import -alias clientkey -file client.crt -keystore clientCrt.keystore

如此一來,生成的檔案分成兩組

服務端儲存:serverKey.keystore clientCrt.keystore

客戶端儲存:clientKey.keystore serverCrt.kyestore

client採用clientKey.keystore中的clientkey私鑰進行資料加密,傳送給server

server採用clientCrt.keystore中的client.crt證書(包含了clientkey的公鑰)對資料解密,如果解密成功,證明訊息來自client,進行邏輯處理

server採用serverKey.keystore中的serverkey私鑰進行資料叫米,傳送給client

client採用serverCrt.kyestore中的server.crt證書(包含了serverkey的公鑰)對資料解密,如果解密成功,證明訊息來自server,進行邏輯處理

如果過程中,解密失敗,那麼證明訊息來源錯誤。不進行邏輯處理。這樣就完成了雙向的身份認證。

tomcat配置:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"

               maxThreads="150" scheme="https" secure="true"

               clientAuth="true" sslProtocol="TLS" 

               keystoreFile="f:\serverKey.keystore" keystorePass="123123" keystoreType="JKS" 

  truststoreFile="f:\clientCrt.keystore" truststorePass="123123" truststoreType="JKS"

  />

private DefaultHttpClient getMutualAuthSSLHttpClient(int sslPort) throws Exception {

httpclient = new DefaultHttpClient();

String CLIENT_KEY_STORE_PASSWORD = "123123";

String CLIENT_TRUST_KEY_STORE_PASSWORD = "123123";

String CLIENT_KEY_PATH = "clientKey.keystore";//client's private key

String SERVER_CERT_PATH = "serverCrt.keystore";//server's certificate

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

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

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

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

KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream(CLIENT_KEY_PATH), CLIENT_KEY_STORE_PASSWORD.toCharArray());

tks.load(new FileInputStream(SERVER_CERT_PATH), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());

kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());

tmf.init(tks);

sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        SSLSocketFactory sf = new SSLSocketFactory(sslContext);

Scheme sch = new Scheme("https", sslPort, sf);

        httpclient.getConnectionManager().getSchemeRegistry().register(sch);

return httpclient;

}

參考 :http://www.sunchis.com/html/java/javaweb/2010/0314/71.html