1. 程式人生 > >eclipse中使用Jetty外掛實現https請求與SSL雙向驗證

eclipse中使用Jetty外掛實現https請求與SSL雙向驗證

連結

完整程式原始碼下載,csdn還沒驗證通過
1. 包含https和socket兩種ssl測試程式碼
2. 所有密碼均為123456

環境準備

  • eclipse中安裝run-jetty-run外掛 csdn下載資源
  • java環境支援,需要使用keytool命令

開始

生成伺服器證書

  1. keytool -genkey -alias serverkey -keyalg RSA -keystore kserver.keystore
  2. keytool -export -alias serverkey -keystore kserver.keystore -rfc -file server.crt
  3. keytool -import -alias serverkey -file server.crt -keystore tclient.keystore

這裡寫圖片描述
其中:kserver.keystore就是服務使用的keystore,server.crt是證書,tclient.keystore是給客戶端使用的信任keystore

特別說明:這裡我們使用自己的keystore直接匯出證書,僅在自己的內部系統可用,如果希望在公網可用,應生成crs向ca申請證書

生成客戶端證書

JKS方式

  1. keytool -genkey -alias clientKey -keystore kclient.keystore
  2. keytool -export -alias clientKey -keystore kclient.keystore -file client.crt
  3. keytool -import -alias clientKey -file client.crt -keystore tserver.keystore

PKCS12方式

  1. keytool -genkeypair -alias clientkey -keyalg RSA -storetype PKCS12 -keystore client.p12
  2. keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.crt
  3. keytool -import -alias clientKey -file client.crt -keystore tserver.keystore

配置Jetty環境

這裡寫圖片描述

特別說明:這裡單獨配置了jetty.xml檔案,因為無法確認jetty在做雙向驗證時候的可信證書從哪裡找的,所以通過jetty.xml檔案來指定位置。如果使用單向驗證,那麼可以直接使用jetty的ssl配置即可。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Call name="addConnector">
     <Arg>
       <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
         <Arg>
           <New class="org.eclipse.jetty.http.ssl.SslContextFactory">
             <Set name="keyStore">D:/workspace/SSLServer/src/ssl/keystore/server/kserver.keystore</Set>
             <Set name="keyStorePassword">123456</Set>
             <Set name="keyManagerPassword">123456</Set>
             <!-- JSK -->
             <Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/client/tserver.keystore</Set>
             <!-- PKCS12 -->
             <!--<Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/pk12/tserver.keystore</Set>-->
             <Set name="trustStorePassword">123456</Set>
             <Set name="needClientAuth">true</Set>
           </New>
         </Arg>
         <Set name="port">8443</Set>
         <Set name="maxIdleTime">30000</Set>
       </New>
     </Arg>
   </Call>
</Configure>

客戶端請求程式碼

package ssl.https;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

public class SSLSayClient {

    private static final String CLIENT_KEY_STORE_PASSWORD = "123456";
    private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";

    private SSLSocketFactory ssLSocketFactory;

    public static void main(String[] args) throws Exception {
        String path = "https://192.168.1.83:8443/SSLServer/say";
        SSLSayClient client = new SSLSayClient();
        client.init();// 雙向驗證
        // client.initOneWay();// 單向驗證
        client.doPost(path);
    }

    static {
        // 預設ip地址校驗通過
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    }

    /**
     * 雙向驗證
     */
    public void init() {
        try {
            SSLContext ctx = SSLContext.getInstance("SSL");

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

            KeyStore ks = KeyStore.getInstance("JKS");// JKS
            // KeyStore ks = KeyStore.getInstance("PKCS12");// PKCS12
            KeyStore tks = KeyStore.getInstance("JKS");

            // JSK
            ks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/client/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
            // PKCS12
            // ks.load(new
            // FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/pk12/client.p12"),
            // CLIENT_KEY_STORE_PASSWORD.toCharArray());
            tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());

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

            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

            ssLSocketFactory = ctx.getSocketFactory();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * 單向驗證
     */
    public void initOneWay() {
        try {
            SSLContext ctx = SSLContext.getInstance("SSL");

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

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

            tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());

            tmf.init(tks);

            ctx.init(null, tmf.getTrustManagers(), new SecureRandom());

            ssLSocketFactory = ctx.getSocketFactory();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * POST
     */
    public void doPost(String path) throws Exception {
        if (ssLSocketFactory == null) {
            System.out.println("ERROR");
            return;
        }
        // 建立URL物件
        URL myURL = new URL(path);
        // 建立HttpsURLConnection物件,並設定其SSLSocketFactory物件
        HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();
        httpsConn.setSSLSocketFactory(ssLSocketFactory);

        String encoding = "UTF-8";
        byte[] data = "Hello Server".getBytes(encoding);

        httpsConn.setRequestMethod("POST");
        httpsConn.setDoOutput(true);
        httpsConn.setRequestProperty("Content-Type", "application/json; charset=" + encoding);
        httpsConn.setRequestProperty("Content-Length", String.valueOf(data.length));
        OutputStream outStream = httpsConn.getOutputStream();
        outStream.write(data);
        outStream.flush();
        outStream.close();
        BufferedReader a = new BufferedReader(new InputStreamReader(httpsConn.getInputStream(), "UTF-8"));
        String line = null;
        while ((line = a.readLine()) != null) {
            System.out.println(line);
        }
    }
}

服務端程式碼

package ssl.https;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Say extends HttpServlet {

    private static final long serialVersionUID = -840442603737824400L;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Server Get");
        String encoding = "UTF-8";
        response.setContentType("application/json; charset=" + encoding);
        OutputStream outStream = response.getOutputStream();
        outStream.write("Hello Client Get".getBytes(encoding));
        outStream.flush();
        outStream.close();
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Server Post");
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

        String encoding = "UTF-8";
        response.setContentType("application/json; charset=" + encoding);
        OutputStream outStream = response.getOutputStream();
        outStream.write("Hello Client Post".getBytes(encoding));

        outStream.flush();
        outStream.close();
    }
}

驗證

啟動jetty伺服器

提示以下資訊,證明伺服器啟動正常

2016-02-23 10:38:52.628:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/SSLServer,[file:/D:/workspace/SSLServer/WebContent/]}
2016-02-23 10:38:52.710:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8088
2016-02-23 10:38:52.896:INFO:oejus.SslContextFactory:Enabled Protocols [SSLv2Hello, SSLv3, TLSv1] of [SSLv2Hello, SSLv3, TLSv1]
2016-02-23 10:38:52.899:INFO:oejs.AbstractConnector:Started SslSelectChannelConnector@0.0.0.0:8443

執行客戶端ssl雙向請求

如果請求成功,將出現如下資訊:
客戶端提示:
Hello Client Post
服務端提示:
Server Post
Hello Server